513 lines
17 KiB
JavaScript
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,
|
|
}
|
|
}
|