qcast-front/src/hooks/floorPlan/estimate/useEstimateController.js
2025-03-14 17:26:59 +09:00

513 lines
17 KiB
JavaScript

import { useAxios } from '@/hooks/useAxios'
import { useContext, useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { globalLocaleStore } from '@/store/localeAtom'
import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { isObjectNotEmpty, isEmptyArray } from '@/util/common-utils'
import { SessionContext } from '@/app/SessionProvider'
import { useMessage } from '@/hooks/useMessage'
import { useRouter, useSearchParams } from 'next/navigation'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { QcastContext } from '@/app/QcastProvider'
import { useSwal } from '@/hooks/useSwal'
// Constants
const ESTIMATE_API_ENDPOINT = '/api/estimate' // API 엔드포인트 정의
// Helper functions
const updateItemInList = (itemList, dispOrder, updates) => {
return itemList.map((item) => (item.dispOrder === dispOrder ? { ...item, ...updates } : item))
}
export const useEstimateController = (planNo, flag) => {
const { swalFire } = useSwal()
const [fileList, setFileList] = useState([])
const { setIsGlobalLoading } = useContext(QcastContext)
const router = useRouter()
const { session } = useContext(SessionContext)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const objectRecoil = useRecoilValue(floorPlanObjectState)
const [estimateData, setEstimateData] = useRecoilState(estimateState)
const { getMessage } = useMessage()
const { promiseGet, post, promisePost } = useAxios(globalLocaleState)
const [isLoading, setIsLoading] = useState(false)
const { estimateContextState, setEstimateContextState } = useContext(FloorPlanContext)
const searchParams = useSearchParams()
useEffect(() => {
if (planNo && !isLoading) {
//견적서 화면에서 새로고침시 리코일 사라지는 현상 대응
let recoilObjectNo = objectRecoil.floorPlanObjectNo ? objectRecoil.floorPlanObjectNo : searchParams.get('objectNo')
if (recoilObjectNo && planNo) {
if (!flag) {
fetchSetting(recoilObjectNo, planNo)
}
}
}
}, [])
useEffect(() => {
if (fileList.length > 0) {
realSave(fileList)
}
}, [fileList])
// 상세 조회
const fetchSetting = async (objectNo, planNo, resetFlag) => {
try {
await promiseGet({ url: `/api/estimate/${objectNo}/${planNo}/detail` }).then((res) => {
setIsGlobalLoading(true)
if (res.status === 200) {
if (isObjectNotEmpty(res.data)) {
if (resetFlag) {
res.data.originFiles = []
res.data.originFile = []
res.data.resetFlag = 'Y'
} else {
res.data.resetFlag = 'N'
}
if (res.data.itemList.length > 0) {
res.data.itemList.map((item) => {
item.delFlg = '0'
})
}
if (res.data.pkgAsp === null || res.data.pkgAsp == undefined) {
res.data.pkgAsp = '0.00'
} else {
const number = parseFloat(res.data.pkgAsp)
const roundedNumber = isNaN(number) ? '0.00' : number.toFixed(2)
res.data.pkgAsp = roundedNumber.toString()
}
setEstimateContextState(res.data)
} else {
swalFire({ text: getMessage('stuff.detail.header.notExistObjectNo'), type: 'alert', icon: 'error' })
setIsLoading(true)
setIsGlobalLoading(false)
}
}
})
setIsLoading(true)
setIsGlobalLoading(false)
} catch (error) {
console.error('견적서 상세조회 Error: ', error)
swalFire({ text: getMessage('stuff.detail.header.notExistObjectNo'), type: 'alert', icon: 'error' })
setIsLoading(true)
setIsGlobalLoading(false)
}
}
const updateItem = (dispOrder, updates) => {
setEstimateContextState({
itemList: updateItemInList(estimateContextState.itemList, dispOrder, updates),
})
}
const addItem = () => {
let newItemDispOrder = estimateContextState.itemList.length === 0 ? 0 : Math.max(...estimateContextState.itemList.map((item) => item.dispOrder))
newItemDispOrder = (Math.floor(newItemDispOrder / 100) + 1) * 100
setEstimateContextState({
itemList: [
...estimateContextState.itemList,
{
objectNo: objectRecoil.floorPlanObjectNo,
planNo: planNo,
dispOrder: newItemDispOrder.toString(),
itemId: '', //제품번호
itemNo: '',
itemName: '', //형명
amount: '', //수량
unitPrice: '0',
unit: '', //단위
salePrice: '', //단가
saleTotPrice: '', //금액(부가세별도)
itemChangeFlg: '1', //추가시 체인지플래그 1로
partAdd: '1', //NEW 체인지 플래그
delFlg: '0', //삭제 플래그 0 삭제하면 1
addFlg: true,
paDispOrder: null,
dispCableFlg: '0',
},
],
})
}
useEffect(() => {
setEstimateData({ ...estimateContextState, userId: session.userId, sapSalesStoreCd: session.custCd })
}, [estimateContextState])
// 첨부파일 다운로드
const handleEstimateFileDownload = async (originFile) => {
const options = { responseType: 'blob' }
await promisePost({ url: `/api/file/fileDownload`, data: originFile, option: options })
.then((resultData) => {
if (resultData) {
const blob = new Blob([resultData.data], { type: resultData.headers['content-type'] || 'application/octet-stream' })
const fileUrl = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = fileUrl
link.download = originFile.faileName
document.body.appendChild(link)
link.click()
link.remove()
window.URL.revokeObjectURL(fileUrl)
}
})
.catch((error) => {
console.log('::FileDownLoad Error::', error)
return swalFire({ text: getMessage('File does not exist'), type: 'alert' })
})
}
//견적서 저장
const handleEstimateSubmit = async () => {
//0. 필수체크
let flag = true
let originFileFlg = false
let fileFlg = true
let itemFlg = true
if (estimateData?.charger === null || estimateData?.charger?.trim().length === 0) {
flag = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredCharger'), type: 'alert', icon: 'warning' })
}
if (estimateData?.objectName === null || estimateData?.objectName?.trim().length === 0) {
flag = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredObjectName'), type: 'alert', icon: 'warning' })
}
if (isNaN(Date.parse(estimateData.estimateDate))) {
flag = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateDate'), type: 'alert', icon: 'warning' })
}
if (estimateData.estimateType === 'YJSS') {
let pkgAsp = estimateData.pkgAsp
if (pkgAsp === '0') {
flag = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredPkgAsp'), type: 'alert', icon: 'warning' })
}
}
//기존에 첨부된 파일이 있으면 파일첨부관련 통과
if (estimateData?.originFiles?.length > 0) {
let cnt = estimateData.originFiles.filter((file) => file.delFlg === '0').length
if (cnt == 0) {
originFileFlg = false
} else {
originFileFlg = true
}
}
if (flag) {
if (!originFileFlg) {
//기존에 첨부된 파일이 없으면
if (isEmptyArray(estimateData.newFileList)) {
//새로 첨부한 파일이 없으면
//북면 먼저 체크
if (estimateData.fileFlg === '0') {
if (estimateData?.northArrangement === '1') {
fileFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredNorthArrangementFileUpload'), type: 'alert', icon: 'warning' })
}
}
if (estimateData.itemList.length > 1) {
estimateData.itemList.map((row) => {
if (row.delFlg === '0') {
if (row.fileUploadFlg === '1') {
if (fileFlg) {
if (estimateData.fileFlg === '0') {
fileFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredFileUpload'), type: 'alert', icon: 'warning' })
}
}
}
}
})
}
}
}
}
if (fileFlg) {
estimateData.itemList.map((item) => {
if (item.delFlg === '0') {
if (item.addFlg) {
if (item.itemId === '') {
itemFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredItemId'), type: 'alert', icon: 'warning' })
}
}
item.amount = item.amount?.replaceAll(',', '')
item.salePrice = Number(item.salePrice?.replaceAll(',', '')).toFixed(2)
item.saleTotPrice = Number(item.saleTotPrice?.replaceAll(',', '')).toFixed(2)
if (!item.paDispOrder) {
if (itemFlg) {
if (isNaN(item.amount)) {
item.amount = '0'
}
if (item.amount < 1) {
itemFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredAmount'), type: 'alert', icon: 'warning' })
}
if (estimateData.estimateType !== 'YJSS') {
if (isNaN(item.salePrice)) {
item.salePrice = '0'
}
if (item.openFlg !== '1') {
if (item.salePrice < 1) {
itemFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredSalePrice'), type: 'alert', icon: 'warning' })
}
}
estimateData.pkgAsp = '0'
estimateData.pkgTotPrice = '0'
} else {
if (item.pkgMaterialFlg === '1') {
if (isNaN(item.salePrice)) {
itemFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredSalePrice'), type: 'alert', icon: 'warning' })
}
}
}
}
} else {
//견적서를 복사하면 API에서 봄컴포넌트는 salePrice, unitPrice를 0으로 내려옴..front에서 처리
if (item.salePrice === null) {
item.salePrice = '0'
} else if (isNaN(item.salePrice)) {
item.salePrice = '0'
}
if (item.unitPrice === null) {
item.unitPrice = '0'
} else if (isNaN(item.unitPrice)) {
item.unitPrice = '0'
}
//봄 컴포넌트 제품은 0으로
item.openFlg = '0'
}
}
})
estimateData.itemList = estimateData.itemList.filter((item) => item.delFlg === '0' || !item.addFlg)
let delCnt = 0
estimateData.itemList.map((item) => {
if (item.delFlg === '1') {
delCnt++
}
})
if (delCnt === estimateData.itemList.length) {
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredItem'), type: 'alert', icon: 'warning' })
}
}
if (flag && fileFlg && itemFlg) {
//1. 첨부파일 저장시작
const formData = new FormData()
if (estimateData?.newFileList?.length > 0) {
estimateData.newFileList.forEach((file) => {
formData.append('files', file)
})
formData.append('objectNo', estimateData.objectNo)
formData.append('planNo', estimateData.planNo)
formData.append('category', '10')
formData.append('userId', estimateData.userId)
await post({ url: '/api/file/fileUpload', data: formData }).then((res) => {
setFileList(res)
setIsGlobalLoading(false)
})
} else {
setFileList([])
realSave()
}
}
}
const realSave = async (fileList) => {
//첨부파일저장끝
let option = []
estimateData.itemList.forEach((item) => {
if (item.specialNoteCd) {
let split2 = item.specialNoteCd.split('、')
option = option.concat(split2)
}
})
let estimateOptions = ''
let estimateOptionsArray
estimateData.specialNoteList.map((item) => {
if (item.pkgYn === '0') {
if (item.check) {
if (estimateOptions === '') {
estimateOptions = item.code
} else {
estimateOptions += '、' + item.code
}
}
} else {
if (item.check) {
let flg = '0'
for (let i = 0; i < estimateData.uniqueData.length; i++) {
if (item.code.indexOf(estimateData.uniqueData[i]) > -1) {
flg = '1'
}
if (flg === '1') {
estimateOptions += '、' + estimateData.uniqueData[i]
}
}
}
}
})
estimateOptionsArray = estimateOptions.split('、').sort()
estimateOptionsArray = Array.from(new Set(estimateOptionsArray))
estimateOptions = estimateOptionsArray.join('、')
estimateData.estimateOption = estimateOptions
// console.log('최종아이템:::', estimateData.itemList)
if (fileList?.length > 0) {
estimateData.fileList = fileList
} else {
estimateData.fileList = []
}
if (estimateData.originFiles?.length > 0) {
estimateData.deleteFileList = estimateData.originFiles?.filter((item) => item.delFlg === '1')
} else {
estimateData.deleteFileList = []
}
if (estimateData.estimateType === 'YJSS') {
estimateData.pkgAsp = estimateData.pkgAsp.replaceAll(',', '')
}
//2. 상세데이터 저장
try {
setIsGlobalLoading(true)
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
if (res.status === 201) {
estimateData.newFileList = []
swalFire({ text: getMessage('estimate.detail.save.alertMsg'), type: 'alert' })
fetchSetting(estimateData.objectNo, estimateData.planNo)
}
})
} catch (e) {
setIsGlobalLoading(false)
console.error('error::::::::::::', e.response.data.message)
}
}
/**
* 견적서 복사버튼
* (견적서 번호(estimateData.docNo)가 생성된 이후 버튼 활성화 )
* T01관리자 계정 및 1차판매점에게만 제공
*/
const handleEstimateCopy = async (sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId, setEstimateCopyPopupOpen) => {
if (saleStoreId === '') {
return swalFire({
text: getMessage('estimate.detail.productFeaturesPopup.requiredStoreId'),
type: 'alert',
icon: 'warning',
})
}
if (copyReceiveUser.trim().length === 0) {
return swalFire({
text: getMessage('estimate.detail.productFeaturesPopup.requiredReceiveUser'),
type: 'alert',
icon: 'warning',
})
} else {
if (checkLength(copyReceiveUser.trim()) > 10) {
return swalFire({ text: getMessage('stuff.detail.tempSave.message2'), type: 'alert', icon: 'warning' })
}
}
const params = {
saleStoreId: session.storeId,
sapSalesStoreCd: session.custCd,
objectNo: estimateData.objectNo,
planNo: sendPlanNo,
copySaleStoreId: otherSaleStoreId ? otherSaleStoreId : saleStoreId,
copyReceiveUser: copyReceiveUser,
userId: session.userId,
}
setIsGlobalLoading(true)
await promisePost({ url: '/api/estimate/save-estimate-copy', data: params }).then((res) => {
setIsGlobalLoading(false)
if (res.status === 201) {
if (isObjectNotEmpty(res.data)) {
let newObjectNo = res.data.objectNo
swalFire({
text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessage'),
type: 'alert',
confirmFn: () => {
setEstimateCopyPopupOpen(false) //팝업닫고
router.push(`/management/stuff/detail?objectNo=${newObjectNo.toString()}`, { scroll: false })
},
})
}
} else {
setIsGlobalLoading(false)
}
})
}
const checkLength = (value) => {
let str = new String(value)
let _byte = 0
if (str.length !== 0) {
for (let i = 0; i < str.length; i++) {
let str2 = str.charAt(i)
if (encodeURIComponent(str2).length > 4) {
_byte += 2
} else {
_byte++
}
}
}
return _byte
}
return {
estimateContextState,
setEstimateContextState,
updateItem,
addItem,
handleEstimateSubmit,
fetchSetting,
handleEstimateFileDownload,
handleEstimateCopy,
}
}