3260 lines
136 KiB
Java
3260 lines
136 KiB
Java
package com.interplug.qcast.biz.estimate;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.math.BigDecimal;
|
|
import java.math.RoundingMode;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.URL;
|
|
import java.net.URLConnection;
|
|
import java.net.URLDecoder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
|
|
import com.interplug.qcast.biz.canvaspopupstatus.CanvasPopupStatusService;
|
|
import com.interplug.qcast.biz.canvaspopupstatus.dto.CanvasPopupStatus;
|
|
import com.interplug.qcast.biz.estimate.dto.*;
|
|
|
|
import com.interplug.qcast.biz.pwrGnrSimulation.dto.PwrGnrSimRoofResponse;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.apache.poi.ss.usermodel.Cell;
|
|
import org.apache.poi.ss.usermodel.CellStyle;
|
|
import org.apache.poi.ss.usermodel.CellType;
|
|
import org.apache.poi.ss.usermodel.DataFormat;
|
|
import org.apache.poi.ss.usermodel.Drawing;
|
|
import org.apache.poi.ss.usermodel.PictureData;
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|
import org.apache.poi.ss.usermodel.Workbook;
|
|
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
|
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
|
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
|
import org.apache.poi.xssf.usermodel.XSSFPicture;
|
|
import org.apache.poi.xssf.usermodel.XSSFShape;
|
|
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|
import org.apache.poi.util.Units;
|
|
import org.jsoup.nodes.Document;
|
|
import org.jsoup.nodes.Element;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.http.HttpMethod;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.web.util.HtmlUtils;
|
|
import org.springframework.web.util.UriComponentsBuilder;
|
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
import com.interplug.qcast.biz.canvasStatus.CanvasStatusService;
|
|
import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatusCopyRequest;
|
|
import com.interplug.qcast.biz.file.FileMapper;
|
|
import com.interplug.qcast.biz.file.dto.FileRequest;
|
|
import com.interplug.qcast.biz.file.dto.FileResponse;
|
|
import com.interplug.qcast.biz.object.ObjectMapper;
|
|
import com.interplug.qcast.biz.object.dto.ObjectRequest;
|
|
import com.interplug.qcast.biz.object.dto.ObjectResponse;
|
|
import com.interplug.qcast.biz.pwrGnrSimulation.PwrGnrSimService;
|
|
import com.interplug.qcast.biz.pwrGnrSimulation.dto.PwrGnrSimGuideResponse;
|
|
import com.interplug.qcast.biz.pwrGnrSimulation.dto.PwrGnrSimRequest;
|
|
import com.interplug.qcast.biz.pwrGnrSimulation.dto.PwrGnrSimResponse;
|
|
import com.interplug.qcast.config.Exception.ErrorCode;
|
|
import com.interplug.qcast.config.Exception.QcastException;
|
|
import com.interplug.qcast.config.message.Messages;
|
|
import com.interplug.qcast.util.ExcelUtil;
|
|
import com.interplug.qcast.util.InterfaceQsp;
|
|
import com.interplug.qcast.util.PdfUtil;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
@Slf4j
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class EstimateService {
|
|
private final InterfaceQsp interfaceQsp;
|
|
|
|
@Autowired
|
|
Messages message;
|
|
|
|
@Value("${file.ini.root.path}")
|
|
private String baseDirPath;
|
|
|
|
@Value("${file.ini.drawing.img.path}")
|
|
private String drawingDirPath;
|
|
|
|
@Value("${qsp.url}")
|
|
private String QSP_API_URL;
|
|
|
|
@Value("${front.url}")
|
|
private String frontUrl;
|
|
|
|
private final ObjectMapper objectMapper;
|
|
|
|
private final EstimateMapper estimateMapper;
|
|
|
|
private final FileMapper fileMapper;
|
|
|
|
@Autowired
|
|
private CanvasStatusService canvasStatusService;
|
|
|
|
@Autowired
|
|
private PwrGnrSimService pwrGnrSimService;
|
|
|
|
@Autowired
|
|
private CanvasPopupStatusService canvasPopupStatusService;
|
|
|
|
/**
|
|
* QSP 1차점 price 관리 목록 조회
|
|
*
|
|
* @param priceRequest 1차점 price 관련 정보
|
|
* @return PriceResponse 1차점 price 목록
|
|
* @throws Exception
|
|
*/
|
|
public EstimateApiResponse selectStorePriceList(PriceRequest priceRequest) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(priceRequest.getSaleStoreId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Sale Store ID"));
|
|
}
|
|
if (StringUtils.isEmpty(priceRequest.getSapSalesStoreCd())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Sap Sale Store Code"));
|
|
}
|
|
if (StringUtils.isEmpty(priceRequest.getDocTpCd())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Estimate Type"));
|
|
}
|
|
|
|
EstimateApiResponse response = null;
|
|
/* [1]. QSP API (url + param) Setting */
|
|
String url = QSP_API_URL + "/api/price/storePriceList";
|
|
String apiUrl = UriComponentsBuilder.fromHttpUrl(url)
|
|
.queryParam("saleStoreId", priceRequest.getSaleStoreId())
|
|
.queryParam("sapSalesStoreCd", priceRequest.getSapSalesStoreCd())
|
|
.queryParam("docTpCd", priceRequest.getDocTpCd()).build().toUriString();
|
|
|
|
/* [2]. QSP API CALL -> Response */
|
|
String strResponse = interfaceQsp.callApi(HttpMethod.GET, apiUrl, null);
|
|
|
|
if (!"".equals(strResponse)) {
|
|
com.fasterxml.jackson.databind.ObjectMapper om =
|
|
new com.fasterxml.jackson.databind.ObjectMapper()
|
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
response = om.readValue(strResponse, EstimateApiResponse.class);
|
|
} else {
|
|
// [msg] No data
|
|
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* QSP 아이템 가격 목록 조회
|
|
*
|
|
* @param priceRequest QSP 관련 아이템 목록 정보
|
|
* @return PriceResponse QSP 아이템 가격 목록
|
|
* @throws Exception
|
|
*/
|
|
public EstimateApiResponse selectItemPriceList(PriceRequest priceRequest) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(priceRequest.getSaleStoreId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Sale Store ID"));
|
|
}
|
|
if (StringUtils.isEmpty(priceRequest.getSapSalesStoreCd())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Sap Sale Store Code"));
|
|
}
|
|
if (StringUtils.isEmpty(priceRequest.getPriceCd())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Price Code"));
|
|
}
|
|
|
|
EstimateApiResponse response = null;
|
|
/* [1]. QSP API CALL -> Response */
|
|
String strResponse = interfaceQsp.callApi(HttpMethod.POST,
|
|
QSP_API_URL + "/api//price/storePriceItemList", priceRequest);
|
|
|
|
if (!"".equals(strResponse)) {
|
|
com.fasterxml.jackson.databind.ObjectMapper om =
|
|
new com.fasterxml.jackson.databind.ObjectMapper()
|
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
response = om.readValue(strResponse, EstimateApiResponse.class);
|
|
} else {
|
|
// [msg] No data
|
|
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* 견적 특이사항 타이틀 목록 조회
|
|
*
|
|
* @param noteRequest 견적 특이사항 조회 정보
|
|
* @return List<NoteResponse> 견적 특이사항 목록
|
|
* @throws Exception
|
|
*/
|
|
public List<NoteResponse> selectSpecialNoteTitleList(NoteRequest noteRequest) throws Exception {
|
|
return estimateMapper.selectEstimateNoteTitleList(noteRequest);
|
|
}
|
|
|
|
/**
|
|
* 견적 특이사항 목록 조회
|
|
*
|
|
* @param noteRequest 견적 특이사항 조회 정보
|
|
* @return List<NoteResponse> 견적 특이사항 목록
|
|
* @throws Exception
|
|
*/
|
|
public List<NoteResponse> selectSpecialNoteList(NoteRequest noteRequest) throws Exception {
|
|
return estimateMapper.selectEstimateNoteList(noteRequest);
|
|
}
|
|
|
|
/**
|
|
* 견적서 상세 조회
|
|
*
|
|
* @param objectNo 물건번호
|
|
* @param planNo 플랜번호
|
|
* @return EstimateResponse 견적서 상세 정보
|
|
* @throws Exception
|
|
*/
|
|
public EstimateResponse selectEstimateDetail(String objectNo, String planNo) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(objectNo)) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(planNo)) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
|
|
String splitStr = "、";
|
|
EstimateRequest estimateRequest = new EstimateRequest();
|
|
estimateRequest.setObjectNo(objectNo);
|
|
estimateRequest.setPlanNo(planNo);
|
|
|
|
// 견적서 상세 조회
|
|
EstimateResponse response = estimateMapper.selectEstimateDetail(estimateRequest);
|
|
|
|
if (response == null) {
|
|
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
|
|
} else {
|
|
|
|
// Plan에서 지붕재, 시공방법 동일 데이타 중복 제거
|
|
String roofCheckDatas = "";
|
|
String roofMaterialIdMultis = "";
|
|
String constructSpecificationMultis = "";
|
|
String orgRoofMaterialIdMultis = response.getRoofMaterialIdMulti();
|
|
String orgConstructSpecificationMultis = response.getConstructSpecificationMulti();
|
|
|
|
if (!StringUtils.isEmpty(orgRoofMaterialIdMultis)
|
|
&& !StringUtils.isEmpty(orgConstructSpecificationMultis)) {
|
|
String[] arrOrgRoofMaterialIdMultis = orgRoofMaterialIdMultis.split(splitStr);
|
|
String[] arrOrgConstructSpecificationMultis =
|
|
orgConstructSpecificationMultis.split(splitStr);
|
|
|
|
if (arrOrgRoofMaterialIdMultis.length == arrOrgConstructSpecificationMultis.length) {
|
|
for (int i = 0; i < arrOrgRoofMaterialIdMultis.length; i++) {
|
|
|
|
if (!roofCheckDatas.contains(
|
|
arrOrgRoofMaterialIdMultis[i] + "_" + arrOrgConstructSpecificationMultis[i])) {
|
|
roofMaterialIdMultis +=
|
|
StringUtils.isEmpty(roofMaterialIdMultis) ? arrOrgRoofMaterialIdMultis[i]
|
|
: splitStr + arrOrgRoofMaterialIdMultis[i];
|
|
constructSpecificationMultis += StringUtils.isEmpty(constructSpecificationMultis)
|
|
? arrOrgConstructSpecificationMultis[i]
|
|
: splitStr + arrOrgConstructSpecificationMultis[i];
|
|
}
|
|
|
|
roofCheckDatas +=
|
|
arrOrgRoofMaterialIdMultis[i] + "_" + arrOrgConstructSpecificationMultis[i];
|
|
}
|
|
|
|
if (!StringUtils.isEmpty(roofMaterialIdMultis)) {
|
|
response.setRoofMaterialIdMulti(roofMaterialIdMultis);
|
|
}
|
|
if (!StringUtils.isEmpty(roofMaterialIdMultis)) {
|
|
response.setConstructSpecificationMulti(constructSpecificationMultis);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 아이템 목록 조회
|
|
List<ItemResponse> estimateItemList = estimateMapper.selectEstimateItemList(estimateRequest);
|
|
response.setItemList(estimateItemList);
|
|
|
|
// 총 합산금액 계산
|
|
this.selectTotalPriceInfo(response, estimateItemList, "");
|
|
|
|
// 첨부파일 목록 조회
|
|
FileRequest fileDeleteReq = new FileRequest();
|
|
fileDeleteReq.setObjectNo(objectNo);
|
|
fileDeleteReq.setCategory("10");
|
|
fileDeleteReq.setPlanNo(planNo);
|
|
|
|
List<FileResponse> fileList = fileMapper.selectFileList(fileDeleteReq);
|
|
response.setFileList(fileList);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* 견적서 저장
|
|
*
|
|
* @param estimateRequest 견적서 저장 정보
|
|
* @throws Exception
|
|
*/
|
|
public void insertEstimate(EstimateRequest estimateRequest) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(estimateRequest.getObjectNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getPlanNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getSaleStoreId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Sale Store ID"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getUserId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "User ID"));
|
|
}
|
|
|
|
List<ItemRequest> circuitItemList = estimateRequest.getCircuitItemList(); //drawingFlg != "1" 인 경우 (도면 없이 저장) circuitItemList는 비어있어도 정상
|
|
List<ItemRequest> itemList = estimateRequest.getItemList();
|
|
|
|
if (itemList == null || itemList.isEmpty()) {
|
|
try {
|
|
Map<String, String> errReq = new HashMap<>();
|
|
errReq.put("objectNo", estimateRequest.getObjectNo());
|
|
errReq.put("planNo", estimateRequest.getPlanNo());
|
|
errReq.put("rejectRsn", "itemList is empty");
|
|
errReq.put("regId", estimateRequest.getUserId());
|
|
interfaceQsp.callApi(HttpMethod.POST, QSP_API_URL + "/api/master/quotationErrSave", errReq);
|
|
} catch (Exception e) {
|
|
log.warn("quotationErrSave failed: {}", e.getMessage());
|
|
}
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "itemList"));
|
|
}
|
|
|
|
String splitStr = "、";
|
|
List<RoofRequest> orgRoofList = new ArrayList<RoofRequest>();
|
|
List<RoofRequest> roofList = new ArrayList<RoofRequest>();
|
|
|
|
estimateRequest.setTempFlg("0");
|
|
|
|
try {
|
|
// 도면 작성일 경우에만 지붕재 데이터를 셋팅
|
|
if ("1".equals(estimateRequest.getDrawingFlg())) {
|
|
// [1]. 견적서 기본셋팅
|
|
// 플랜정보 조회 (임시저장여부 가져오기)
|
|
EstimateResponse estimateResponse = estimateMapper.selectEstimateDetail(estimateRequest);
|
|
estimateRequest.setEstimateType("YJOD");
|
|
estimateRequest.setPriceCd("UNIT_PRICE");
|
|
estimateRequest.setTempFlg("0".equals(estimateResponse.getTempFlg()) ? "0" : "1");
|
|
|
|
// 물건정보 조회 후 데이터 축출
|
|
ObjectResponse objectResponse =
|
|
objectMapper.selectObjectDetail(estimateRequest.getObjectNo());
|
|
if (objectResponse != null) {
|
|
estimateRequest
|
|
.setWeatherPoint(objectResponse.getPrefName() + " - " + objectResponse.getAreaName());
|
|
estimateRequest.setCharger(objectResponse.getReceiveUser());
|
|
}
|
|
|
|
// [2]. 지붕재 관련 데이터 셋팅
|
|
orgRoofList = estimateRequest.getRoofSurfaceList();
|
|
for (RoofRequest roofRequest : orgRoofList) {
|
|
if (!roofRequest.getModuleList().isEmpty()) { // 빈 배열은 지붕재 데이타에서 제거
|
|
roofList.add(roofRequest);
|
|
}
|
|
}
|
|
|
|
// 지붕재 시공사양 ID
|
|
String constructSpecifications = "";
|
|
// 지붕재 아이템 ID
|
|
String roofMaterialIds = "";
|
|
// 지붕재 공법 ID
|
|
String supportMethodIds = "";
|
|
// 지붕재 아이템명
|
|
String roofMaterialIdMultis = "";
|
|
// 지붕재 공법명
|
|
String supportMethodIdMultis = "";
|
|
// 지붕재 시공사양명
|
|
String constructSpecificationMultis = "";
|
|
// 가대 메이커명
|
|
String supportMeakers = "";
|
|
for (RoofRequest roofRequest : roofList) {
|
|
if (!StringUtils.isEmpty(roofRequest.getRoofMaterialId())) {
|
|
roofMaterialIds += !StringUtils.isEmpty(roofMaterialIds) ? splitStr : "";
|
|
roofMaterialIds += roofRequest.getRoofMaterialId();
|
|
}
|
|
|
|
if (!StringUtils.isEmpty(roofRequest.getSupportMethodId())) {
|
|
supportMethodIds += !StringUtils.isEmpty(supportMethodIds) ? splitStr : "";
|
|
supportMethodIds += roofRequest.getSupportMethodId();
|
|
}
|
|
|
|
if (!StringUtils.isEmpty(roofRequest.getConstructSpecification())) {
|
|
constructSpecifications +=
|
|
!StringUtils.isEmpty(constructSpecifications) ? splitStr : "";
|
|
constructSpecifications += roofRequest.getConstructSpecification();
|
|
}
|
|
|
|
if (!StringUtils.isEmpty(roofRequest.getRoofMaterialIdMulti())) {
|
|
roofMaterialIdMultis += !StringUtils.isEmpty(roofMaterialIdMultis) ? splitStr : "";
|
|
roofMaterialIdMultis += roofRequest.getRoofMaterialIdMulti();
|
|
}
|
|
|
|
if (!StringUtils.isEmpty(roofRequest.getSupportMethodIdMulti())) {
|
|
supportMethodIdMultis += !StringUtils.isEmpty(supportMethodIdMultis) ? splitStr : "";
|
|
supportMethodIdMultis += roofRequest.getSupportMethodIdMulti();
|
|
}
|
|
|
|
if (!StringUtils.isEmpty(roofRequest.getConstructSpecificationMulti())) {
|
|
constructSpecificationMultis +=
|
|
!StringUtils.isEmpty(constructSpecificationMultis) ? splitStr : "";
|
|
constructSpecificationMultis += roofRequest.getConstructSpecificationMulti();
|
|
}
|
|
|
|
if (!StringUtils.isEmpty(roofRequest.getSupportMeaker())) {
|
|
supportMeakers += !StringUtils.isEmpty(supportMeakers) ? splitStr : "";
|
|
supportMeakers += roofRequest.getSupportMeaker();
|
|
}
|
|
}
|
|
|
|
// 지붕재 관련 데이터 셋팅
|
|
estimateRequest.setRoofMaterialId(roofMaterialIds);
|
|
estimateRequest.setSupportMethodId(supportMethodIds);
|
|
estimateRequest.setConstructSpecification(constructSpecifications);
|
|
estimateRequest.setRoofMaterialIdMulti(roofMaterialIdMultis);
|
|
estimateRequest.setSupportMethodIdMulti(supportMethodIdMultis);
|
|
estimateRequest.setConstructSpecificationMulti(constructSpecificationMultis);
|
|
estimateRequest.setSupportMeaker(supportMeakers);
|
|
|
|
// [3]. 아이템 관련 데이터 셋팅
|
|
String[] arrItemId = new String[itemList.size()];
|
|
int i = 0;
|
|
for (ItemRequest itemRequest : itemList) {
|
|
arrItemId[i++] = itemRequest.getItemId();
|
|
}
|
|
estimateRequest.setArrItemId(arrItemId);
|
|
// 아이템의 마스터 정보 및 정가 정보 조회
|
|
List<ItemResponse> itemResponseList = estimateMapper.selectItemMasterList(estimateRequest);
|
|
// BOM 정보 목록
|
|
List<ItemRequest> estimateBomList = new ArrayList<ItemRequest>();
|
|
|
|
int j = 1;
|
|
for (ItemRequest itemRequest : itemList) {
|
|
int dispOrder = 100 * j++;
|
|
itemRequest.setDispOrder(String.valueOf(dispOrder));
|
|
|
|
for (ItemResponse itemResponse : itemResponseList) {
|
|
if (itemRequest.getItemId().equals(itemResponse.getItemId())) {
|
|
itemRequest.setItemNo(itemResponse.getItemNo());
|
|
itemRequest.setItemName(itemResponse.getItemName());
|
|
itemRequest.setUnit(itemResponse.getUnit());
|
|
itemRequest.setPnowW(itemResponse.getPnowW());
|
|
itemRequest.setSpecification(itemResponse.getPnowW());
|
|
itemRequest.setUnitPrice(itemResponse.getSalePrice());
|
|
itemRequest.setSalePrice(itemResponse.getSalePrice());
|
|
itemRequest.setFileUploadFlg(itemResponse.getFileUploadFlg());
|
|
itemRequest.setPkgMaterialFlg(itemResponse.getPkgMaterialFlg());
|
|
itemRequest.setOpenFlg(itemResponse.getOpenFlg());
|
|
itemRequest.setUnitOpenFlg(itemResponse.getUnitOpenFlg());
|
|
itemRequest.setDispCableFlg("CABLE_".equals(itemResponse.getItemGroup()) ? "1" : "0");
|
|
itemRequest.setItemGroup(itemResponse.getItemGroup());
|
|
itemRequest.setItemCtgGr(itemResponse.getItemCtgGr());
|
|
itemRequest.setPartAdd("0");
|
|
itemRequest.setDelFlg("0");
|
|
break;
|
|
}
|
|
}
|
|
itemRequest.setNorthModuleYn(itemRequest.getNorthModuleYn());
|
|
// 아이템 BOM Header인 경우 컴포넌트 등록 처리
|
|
if ("ERLA".equals(itemRequest.getItemCtgGr())) {
|
|
List<ItemResponse> itemBomList =
|
|
estimateMapper.selectItemMasterBomList(itemRequest.getItemId());
|
|
|
|
int k = 1;
|
|
for (ItemResponse itemResponse : itemBomList) {
|
|
ItemRequest bomItem = new ItemRequest();
|
|
|
|
bomItem.setPaDispOrder(String.valueOf(dispOrder));
|
|
bomItem.setDispOrder(String.valueOf(dispOrder + k++));
|
|
bomItem.setItemId(itemResponse.getItemId());
|
|
bomItem.setItemNo(itemResponse.getItemNo());
|
|
bomItem.setItemName(itemResponse.getItemName());
|
|
bomItem.setUnit(itemResponse.getUnit());
|
|
bomItem.setPnowW(itemResponse.getPnowW());
|
|
bomItem.setSpecification(itemResponse.getPnowW());
|
|
bomItem.setAmount(String.valueOf(Integer.parseInt(itemResponse.getBomAmount())
|
|
* Integer.parseInt(itemRequest.getAmount())));
|
|
bomItem.setBomAmount(itemResponse.getBomAmount());
|
|
bomItem.setUnitPrice(itemResponse.getSalePrice());
|
|
bomItem.setSalePrice(itemResponse.getSalePrice());
|
|
bomItem.setFileUploadFlg(itemResponse.getFileUploadFlg());
|
|
bomItem.setPkgMaterialFlg(itemResponse.getPkgMaterialFlg());
|
|
bomItem.setOpenFlg("0");
|
|
bomItem.setUnitOpenFlg("0");
|
|
bomItem.setDispCableFlg("0");
|
|
bomItem.setItemGroup(itemResponse.getItemGroup());
|
|
bomItem.setItemCtgGr(itemResponse.getItemCtgGr());
|
|
bomItem.setPartAdd("0");
|
|
bomItem.setDelFlg("0");
|
|
|
|
estimateBomList.add(bomItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
System.out.print("itemRequest");
|
|
// BOM 컴포넌트 추가
|
|
itemList.addAll(estimateBomList);
|
|
|
|
// [4]. 견적특이사항 관련 데이터 셋팅
|
|
NoteRequest noteRequest = new NoteRequest();
|
|
noteRequest.setArrItemId(arrItemId);
|
|
noteRequest.setSchSpnTypeCd("COMM");
|
|
List<NoteResponse> noteList = estimateMapper.selectEstimateNoteList(noteRequest);
|
|
noteRequest.setSchSpnTypeCd("PROD");
|
|
List<NoteResponse> noteItemList = estimateMapper.selectEstimateNoteItemList(noteRequest);
|
|
|
|
// 견적특이사항 코드
|
|
String estimateOptions = "";
|
|
for (NoteResponse noteResponse : noteList) {
|
|
if ("ATTR001".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR001"; // 공통 필수체크
|
|
} else if ("ATTR002".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR002"; // YJOD 필수체크
|
|
} else if ("ATTR003".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR003"; // 출력제어시간 기본 체크
|
|
} else if ("ATTR004".equals(noteResponse.getCode())
|
|
&& "1".equals(estimateRequest.getNorthArrangement())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR004"; // 북면설치 체크
|
|
} else if ("ATTR005".equals(noteResponse.getCode())
|
|
&& "1".equals(objectResponse != null ? objectResponse.getSaltAreaFlg() : "")) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR005"; // 염해지역 체크
|
|
} else if ("ATTR006"
|
|
.equals(objectResponse != null ? objectResponse.getColdRegionFlg() : "")
|
|
&& "1".equals(estimateRequest.getNorthArrangement())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR006"; // 적설지역 체크
|
|
} else if ("ATTR007".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR007"; // 지붕재치수, 레이아웃 기본 체크
|
|
} else if ("ATTR008".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR008"; // 별도비용 기본 체크
|
|
} else if ("ATTR009".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR009"; // 과적재 기본 체크
|
|
}
|
|
}
|
|
for (NoteResponse noteResponse : noteItemList) {
|
|
if (estimateOptions.indexOf(noteResponse.getCode()) < 0) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += noteResponse.getCode();
|
|
}
|
|
}
|
|
estimateRequest.setEstimateOption(estimateOptions);
|
|
|
|
// 아이템별 특이사항 코드 체크
|
|
for (ItemRequest itemRequest : itemList) {
|
|
String specialNoteCd = "";
|
|
for (NoteResponse noteResponse : noteItemList) {
|
|
if (itemRequest.getItemId().equals(noteResponse.getItemId())) {
|
|
specialNoteCd += !StringUtils.isEmpty(specialNoteCd) ? splitStr : "";
|
|
specialNoteCd += noteResponse.getCode();
|
|
}
|
|
}
|
|
itemRequest.setSpecialNoteCd(specialNoteCd);
|
|
}
|
|
|
|
// 첨부파일 초기화
|
|
FileRequest fileRequest = new FileRequest();
|
|
fileRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
fileRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
fileRequest.setUserId(estimateRequest.getUserId());
|
|
fileMapper.deleteFile(fileRequest);
|
|
}
|
|
|
|
// 아이템 목록 필수 값 체크
|
|
BigDecimal capacity = BigDecimal.ZERO;
|
|
String moduleModel = "";
|
|
String pcTypeNo = "";
|
|
for (ItemRequest itemRequest : itemList) {
|
|
if (!"1".equals(itemRequest.getDelFlg())) {
|
|
if (StringUtils.isEmpty(itemRequest.getDispOrder())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Display Order"));
|
|
}
|
|
if (StringUtils.isEmpty(itemRequest.getItemId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Item ID"));
|
|
}
|
|
if (StringUtils.isEmpty(itemRequest.getAmount())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Item Amount"));
|
|
}
|
|
|
|
// 수량
|
|
BigDecimal amount = new BigDecimal(
|
|
StringUtils.isEmpty(itemRequest.getAmount()) ? "0" : itemRequest.getAmount());
|
|
// 아이템용량
|
|
BigDecimal pnowW = new BigDecimal(
|
|
StringUtils.isEmpty(itemRequest.getPnowW()) ? "0" : itemRequest.getPnowW());
|
|
|
|
// 모듈/PC 체크
|
|
if ("MODULE_".equals(itemRequest.getItemGroup())) {
|
|
moduleModel += !StringUtils.isEmpty(moduleModel) ? splitStr : "";
|
|
moduleModel += itemRequest.getItemNo();
|
|
|
|
capacity = capacity.add(amount.multiply(pnowW));
|
|
} else if ("PC_".equals(itemRequest.getItemGroup())) {
|
|
pcTypeNo += !StringUtils.isEmpty(pcTypeNo) ? splitStr : "";
|
|
pcTypeNo += itemRequest.getItemNo();
|
|
} else if ("STORAGE_BATTERY".equals(itemRequest.getItemGroup())) {
|
|
pcTypeNo += !StringUtils.isEmpty(pcTypeNo) ? splitStr : "";
|
|
pcTypeNo += itemRequest.getItemNo();
|
|
}
|
|
}
|
|
}
|
|
estimateRequest.setCapacity(String.valueOf(capacity));
|
|
estimateRequest.setModuleModel(moduleModel);
|
|
estimateRequest.setPcTypeNo(pcTypeNo);
|
|
|
|
// 물건정보 수정
|
|
if (!StringUtils.isEmpty(estimateRequest.getObjectName())
|
|
|| !StringUtils.isEmpty(estimateRequest.getObjectNameOmit())) {
|
|
estimateMapper.updateObject(estimateRequest);
|
|
}
|
|
if (!StringUtils.isEmpty(estimateRequest.getSurfaceType())
|
|
|| !StringUtils.isEmpty(estimateRequest.getSetupHeight())
|
|
|| !StringUtils.isEmpty(estimateRequest.getStandardWindSpeedId())
|
|
|| !StringUtils.isEmpty(estimateRequest.getSnowfall())) {
|
|
estimateMapper.updateObjectInfo(estimateRequest);
|
|
}
|
|
|
|
// 견적서 정보 수정
|
|
estimateRequest.setPriceCd(
|
|
!StringUtils.isEmpty(estimateRequest.getPriceCd()) ? estimateRequest.getPriceCd()
|
|
: "UNIT_PRICE");
|
|
estimateMapper.updateEstimate(estimateRequest);
|
|
estimateMapper.updateEstimateInfo(estimateRequest);
|
|
|
|
// 도면 작성일 경우에만 지붕면, 도면 아이템 데이터 초기화 후 저장
|
|
if ("1".equals(estimateRequest.getDrawingFlg())) {
|
|
// 견적서 지붕면/아이템 및 PC 회로구성도 제거
|
|
estimateMapper.deleteEstimateRoofList(estimateRequest);
|
|
estimateMapper.deleteEstimateRoofItemList(estimateRequest);
|
|
estimateMapper.deleteEstimateCircuitItemList(estimateRequest);
|
|
|
|
// 견적서 지붕면/아이템 신규 추가
|
|
List<ItemRequest> allModuleList = new ArrayList<ItemRequest>();
|
|
for (RoofRequest roofRequest : roofList) {
|
|
roofRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
roofRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
roofRequest.setUserId(estimateRequest.getUserId());
|
|
|
|
estimateMapper.insertEstimateRoof(roofRequest);
|
|
|
|
List<ItemRequest> moduleList = roofRequest.getModuleList();
|
|
List<ItemRequest> roofItemList = new ArrayList<ItemRequest>();
|
|
|
|
// 동일 모듈, PCS 아이템 묶기
|
|
for (ItemRequest itemRequest : moduleList) {
|
|
boolean overLap = false;
|
|
for (ItemRequest data : roofItemList) {
|
|
if (itemRequest.getItemId().equals(data.getItemId())
|
|
&& itemRequest.getPcItemId().equals(data.getPcItemId())) {
|
|
data.setAmount(String.valueOf(Integer.parseInt(data.getAmount()) + 1)); // 데이터 존재하면
|
|
// 카운팅 + 1
|
|
overLap = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!overLap) {
|
|
itemRequest.setAmount("1");
|
|
roofItemList.add(itemRequest);
|
|
}
|
|
|
|
allModuleList.add(itemRequest);
|
|
}
|
|
|
|
for (ItemRequest itemRequest : roofItemList) {
|
|
itemRequest.setRoofSurfaceId(roofRequest.getRoofSurfaceId());
|
|
itemRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
itemRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
// 선택한 PCS 아이템이 다른 경우
|
|
for (ItemRequest itemObj : itemList) {
|
|
if(itemObj.getQcastCustPrdId() != null && itemObj.getQcastCustPrdId().equals(itemRequest.getPcItemId())) {
|
|
itemRequest.setQcastCustPrdId(itemObj.getItemId());
|
|
}
|
|
if(itemObj.getItemId().equals(itemRequest.getItemId())) {
|
|
itemRequest.setNorthModuleYn(itemObj.getNorthModuleYn());
|
|
}
|
|
|
|
}
|
|
estimateMapper.insertEstimateRoofItem(itemRequest);
|
|
}
|
|
}
|
|
|
|
// 견적서 PCS 아이템 회로 구성
|
|
List<ItemRequest> circuitPcsItemList =
|
|
this.getPcsCircuitList(circuitItemList, allModuleList);
|
|
|
|
// 견적서 회로구성 아이템 신규 추가
|
|
for (ItemRequest circuitItemRequest : circuitPcsItemList) {
|
|
circuitItemRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
circuitItemRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
|
|
if (!StringUtils.isEmpty(circuitItemRequest.getCircuitCfg())) {
|
|
estimateMapper.insertEstimateCircuitItem(circuitItemRequest);
|
|
}
|
|
}
|
|
|
|
// 견적서 도면 아이템 제거
|
|
estimateMapper.deleteEstimateDrawingItemList(estimateRequest);
|
|
// 견적서 도면 아이템 등록
|
|
for (ItemRequest itemRequest : itemList) {
|
|
itemRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
itemRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
itemRequest.setAmount(
|
|
!StringUtils.isEmpty(itemRequest.getAmount()) ? itemRequest.getAmount() : "0");
|
|
itemRequest.setUserId(estimateRequest.getUserId());
|
|
|
|
// BOM 컴포넌트는 제외하고 등록
|
|
if (StringUtils.isEmpty(itemRequest.getPaDispOrder())) {
|
|
estimateMapper.insertEstimateDrawingItem(itemRequest);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 견적서 모든 아이템 제거
|
|
estimateMapper.deleteEstimateItemList(estimateRequest);
|
|
estimateMapper.deleteEstimateInfoItemList(estimateRequest);
|
|
|
|
// 견적서 아이템 신규 추가
|
|
String hisNo = estimateMapper.selectEstimateItemHisNo(estimateRequest); // 아이템 히스토리 번호 조회
|
|
for (ItemRequest itemRequest : itemList) {
|
|
itemRequest.setHisNo(hisNo);
|
|
itemRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
itemRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
itemRequest.setAmount(
|
|
!StringUtils.isEmpty(itemRequest.getAmount()) ? itemRequest.getAmount() : "0");
|
|
itemRequest.setSalePrice(
|
|
!StringUtils.isEmpty(itemRequest.getSalePrice()) ? itemRequest.getSalePrice() : "0");
|
|
itemRequest.setBomAmount(
|
|
!StringUtils.isEmpty(itemRequest.getBomAmount()) ? itemRequest.getBomAmount() : "0");
|
|
itemRequest.setPartAdd(
|
|
!StringUtils.isEmpty(itemRequest.getPartAdd()) ? itemRequest.getPartAdd() : "0");
|
|
itemRequest.setOpenFlg(
|
|
!StringUtils.isEmpty(itemRequest.getOpenFlg()) ? itemRequest.getOpenFlg() : "0");
|
|
itemRequest.setUnitOpenFlg(
|
|
!StringUtils.isEmpty(itemRequest.getUnitOpenFlg()) ? itemRequest.getUnitOpenFlg() : "0");
|
|
itemRequest.setItemChangeFlg(
|
|
!StringUtils.isEmpty(itemRequest.getItemChangeFlg()) ? itemRequest.getItemChangeFlg()
|
|
: "0");
|
|
itemRequest.setDispCableFlg(
|
|
!StringUtils.isEmpty(itemRequest.getDispCableFlg()) ? itemRequest.getDispCableFlg()
|
|
: "0");
|
|
itemRequest.setUserId(estimateRequest.getUserId());
|
|
|
|
estimateMapper.insertEstimateItemHis(itemRequest);
|
|
|
|
if (!"1".equals(itemRequest.getDelFlg())) {
|
|
estimateMapper.insertEstimateItem(itemRequest);
|
|
estimateMapper.insertEstimateInfoItem(itemRequest);
|
|
}
|
|
}
|
|
|
|
// 첨부파일 처리
|
|
if (estimateRequest.getFileList() != null) {
|
|
for (FileRequest fileRequest : estimateRequest.getFileList()) {
|
|
fileRequest.setUserId(estimateRequest.getUserId());
|
|
fileMapper.insertFile(fileRequest);
|
|
fileMapper.insertFileInfo(fileRequest);
|
|
}
|
|
}
|
|
|
|
if (estimateRequest.getDeleteFileList() != null) {
|
|
for (FileRequest fileRequest : estimateRequest.getDeleteFileList()) {
|
|
fileRequest.setUserId(estimateRequest.getUserId());
|
|
fileMapper.deleteFile(fileRequest);
|
|
}
|
|
}
|
|
|
|
// 임시저장 상태에서는 인터페이스 막도록 처리
|
|
if ("0".equals(estimateRequest.getTempFlg())) {
|
|
// QSP Q.CAST SEND API
|
|
List<EstimateSendResponse> resultList = new ArrayList<EstimateSendResponse>();
|
|
resultList = this.sendEstimateApi(estimateRequest);
|
|
// API에서 받은 문서번호 업데이트
|
|
for (EstimateSendResponse result : resultList) {
|
|
estimateRequest.setObjectNo(result.getObjectNo());
|
|
estimateRequest.setPlanNo(result.getPlanNo());
|
|
estimateRequest.setDocNo(result.getDocNo());
|
|
estimateRequest.setSyncFlg(result.getSyncFlg());
|
|
|
|
estimateMapper.updateEstimateApi(estimateRequest);
|
|
}
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 견적서 복사
|
|
*
|
|
* @param estimateCopyRequest 견적서 복사 정보
|
|
* @return EstimateResponse 견적서 복사 후 상세 정보
|
|
* @throws Exception
|
|
*/
|
|
public EstimateResponse insertEstimateCopy(EstimateCopyRequest estimateCopyRequest)
|
|
throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(estimateCopyRequest.getObjectNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateCopyRequest.getPlanNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateCopyRequest.getUserId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "User ID"));
|
|
}
|
|
|
|
// 응답 객체
|
|
EstimateResponse response = new EstimateResponse();
|
|
|
|
try {
|
|
|
|
ObjectRequest objectRequest = new ObjectRequest();
|
|
objectRequest.setSaleStoreId(estimateCopyRequest.getCopySaleStoreId());
|
|
objectRequest
|
|
.setReceiveUser(StringUtils.defaultString(estimateCopyRequest.getCopyReceiveUser()));
|
|
objectRequest.setDelFlg("1");
|
|
objectRequest.setOrgDelFlg("0");
|
|
objectRequest.setTempFlg("0");
|
|
objectRequest.setTempDelFlg("0");
|
|
objectRequest.setUserId(estimateCopyRequest.getUserId());
|
|
|
|
// [1]. 신규 물건번호 생성
|
|
objectMapper.insertObjectNo(objectRequest);
|
|
objectRequest.setObjectNo(estimateCopyRequest.getObjectNo());
|
|
objectRequest.setCopyObjectNo(objectMapper.selectObjectNo(objectRequest));
|
|
|
|
// [2]. 물건정보 복사
|
|
objectRequest.setContentsPath(baseDirPath + "\\\\" + objectRequest.getCopyObjectNo());
|
|
objectMapper.insertObjectCopy(objectRequest);
|
|
objectMapper.insertObjectInfoCopy(objectRequest);
|
|
objectRequest.setObjectNo(objectRequest.getCopyObjectNo());
|
|
objectMapper.updateObjectDelivery(objectRequest);
|
|
|
|
// [3]. 아이템 관련 데이터 셋팅 (복사 시 정가 셋팅)
|
|
EstimateRequest estimateRequest = new EstimateRequest();
|
|
estimateRequest.setObjectNo(estimateCopyRequest.getObjectNo());
|
|
estimateRequest.setPlanNo(estimateCopyRequest.getPlanNo());
|
|
|
|
List<ItemRequest> itemList = new ArrayList<ItemRequest>();
|
|
List<ItemResponse> estimateItemList = estimateMapper.selectEstimateItemList(estimateRequest);
|
|
for (ItemResponse itemResponse : estimateItemList) {
|
|
ItemRequest itemRequest = new ItemRequest();
|
|
itemRequest.setDispOrder(itemResponse.getDispOrder());
|
|
itemRequest.setPaDispOrder(itemResponse.getPaDispOrder());
|
|
itemRequest.setItemId(itemResponse.getItemId());
|
|
itemRequest.setItemNo(itemResponse.getItemNo());
|
|
itemRequest.setItemName(itemResponse.getItemName());
|
|
itemRequest.setUnit(itemResponse.getUnit());
|
|
itemRequest.setAmount(itemResponse.getAmount());
|
|
itemRequest.setBomAmount(itemResponse.getBomAmount());
|
|
itemRequest.setSpecialNoteCd(itemResponse.getSpecialNoteCd());
|
|
itemRequest.setItemChangeFlg("0");
|
|
itemRequest.setDispCableFlg(itemResponse.getDispCableFlg());
|
|
|
|
itemList.add(itemRequest);
|
|
}
|
|
|
|
if (!itemList.isEmpty()) {
|
|
String[] arrItemId = new String[itemList.size()];
|
|
int i = 0;
|
|
for (ItemRequest itemRequest : itemList) {
|
|
arrItemId[i++] = itemRequest.getItemId();
|
|
}
|
|
estimateRequest.setArrItemId(arrItemId);
|
|
// 아이템의 마스터 정보 및 정가 정보 조회
|
|
List<ItemResponse> itemResponseList = estimateMapper.selectItemMasterList(estimateRequest);
|
|
|
|
for (ItemRequest itemRequest : itemList) {
|
|
for (ItemResponse itemResponse : itemResponseList) {
|
|
if (itemRequest.getItemId().equals(itemResponse.getItemId())) {
|
|
itemRequest.setItemNo(itemResponse.getItemNo());
|
|
itemRequest.setItemName(itemResponse.getItemName());
|
|
itemRequest.setUnit(itemResponse.getUnit());
|
|
itemRequest.setPnowW(itemResponse.getPnowW());
|
|
itemRequest.setSpecification(itemResponse.getPnowW());
|
|
itemRequest.setUnitPrice(itemResponse.getSalePrice());
|
|
itemRequest.setSalePrice(itemResponse.getSalePrice());
|
|
itemRequest.setPkgMaterialFlg(itemResponse.getPkgMaterialFlg());
|
|
itemRequest.setFileUploadFlg(itemResponse.getFileUploadFlg());
|
|
itemRequest.setItemGroup(itemResponse.getItemGroup());
|
|
itemRequest.setOpenFlg(itemResponse.getOpenFlg());
|
|
itemRequest.setUnitOpenFlg(itemResponse.getUnitOpenFlg());
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// [4]. 견적서 복사
|
|
estimateCopyRequest.setCopyObjectNo(objectRequest.getObjectNo());
|
|
estimateCopyRequest.setCopyPlanNo("1");
|
|
estimateCopyRequest.setCopyReceiveUser(objectRequest.getReceiveUser()); //담당자
|
|
estimateMapper.insertEstimateCopy(estimateCopyRequest);
|
|
estimateMapper.insertEstimateInfoCopy(estimateCopyRequest);
|
|
estimateMapper.insertCanvasPopupStatusCopy(estimateCopyRequest);
|
|
|
|
// [5]. 견적서 아이템 복사
|
|
for (ItemRequest itemRequest : itemList) {
|
|
itemRequest.setObjectNo(estimateCopyRequest.getCopyObjectNo());
|
|
itemRequest.setPlanNo(estimateCopyRequest.getCopyPlanNo());
|
|
itemRequest.setPartAdd(
|
|
!StringUtils.isEmpty(itemRequest.getPartAdd()) ? itemRequest.getPartAdd() : "0");
|
|
itemRequest.setItemChangeFlg(
|
|
!StringUtils.isEmpty(itemRequest.getItemChangeFlg()) ? itemRequest.getItemChangeFlg()
|
|
: "0");
|
|
itemRequest.setUserId(estimateCopyRequest.getUserId());
|
|
|
|
estimateMapper.insertEstimateItem(itemRequest);
|
|
estimateMapper.insertEstimateInfoItem(itemRequest);
|
|
}
|
|
|
|
// [6]. 견적서 지붕면 및 도면 초기 데이터 복사
|
|
// 견적서 지붕면 복사
|
|
estimateMapper.insertEstimateRoofCopy(estimateCopyRequest);
|
|
// 견적서 지붕면 아이템 복사
|
|
estimateMapper.insertEstimateRoofItemCopy(estimateCopyRequest);
|
|
// 견적서 지붕면 회로구성 아이템 복사
|
|
estimateMapper.insertEstimateCircuitItemCopy(estimateCopyRequest);
|
|
// 도면 초기 데이타 복사(초기화 위해 필요)
|
|
estimateMapper.insertEstimateDrawingItemCopy(estimateCopyRequest);
|
|
|
|
// [7]. 견적서 도면 복사
|
|
CanvasStatusCopyRequest cs = new CanvasStatusCopyRequest();
|
|
cs.setOriginObjectNo(estimateCopyRequest.getObjectNo());
|
|
cs.setOriginPlanNo(estimateCopyRequest.getPlanNo());
|
|
cs.setObjectNo(estimateCopyRequest.getCopyObjectNo());
|
|
cs.setPlanNo(estimateCopyRequest.getCopyPlanNo());
|
|
cs.setUserId(estimateCopyRequest.getUserId());
|
|
canvasStatusService.copyCanvasStatus(cs, true);
|
|
|
|
} catch (Exception e) {
|
|
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
|
|
}
|
|
|
|
// [9]. 최종 생성 물건번호 리턴
|
|
response.setObjectNo(estimateCopyRequest.getCopyObjectNo());
|
|
response.setPlanNo(estimateCopyRequest.getCopyPlanNo());
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* 견적서 초기화
|
|
*
|
|
* @param estimateRequest
|
|
* @return EstimateResponse 견적서 초기화 후 상세 정보
|
|
* @throws Exception
|
|
*/
|
|
public EstimateResponse updateEstimateReset(EstimateRequest estimateRequest) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(estimateRequest.getObjectNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getPlanNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getUserId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "User ID"));
|
|
}
|
|
|
|
// 견적서 상세 조회
|
|
EstimateResponse estimateResponse = estimateMapper.selectEstimateDetail(estimateRequest);
|
|
if (estimateResponse == null) {
|
|
throw new QcastException(ErrorCode.NOT_FOUND,
|
|
message.getMessage("common.message.required.data", "Estimate Info"));
|
|
}
|
|
|
|
// 응답 객체
|
|
EstimateResponse response = new EstimateResponse();
|
|
String splitStr = "、";
|
|
|
|
try {
|
|
// [1]. 견적서 기본셋팅
|
|
estimateRequest.setEstimateType("YJOD");
|
|
estimateRequest.setPriceCd("UNIT_PRICE");
|
|
estimateRequest.setTempFlg("0".equals(estimateResponse.getTempFlg()) ? "0" : "1");
|
|
|
|
// 물건정보 조회 후 데이터 축출
|
|
ObjectResponse objectResponse =
|
|
objectMapper.selectObjectDetail(estimateRequest.getObjectNo());
|
|
if (objectResponse != null) {
|
|
estimateRequest
|
|
.setWeatherPoint(objectResponse.getPrefName() + " - " + objectResponse.getAreaName());
|
|
estimateRequest.setCharger(objectResponse.getReceiveUser());
|
|
}
|
|
|
|
// [2] 도면에서 저장된 아이템 목록 조회
|
|
List<ItemResponse> estimateItemList =
|
|
estimateMapper.selectEstimateDrawingItemList(estimateRequest);
|
|
List<ItemRequest> itemList = new ArrayList<ItemRequest>();
|
|
for (ItemResponse itemResponse : estimateItemList) {
|
|
ItemRequest itemRequest = new ItemRequest();
|
|
itemRequest.setObjectNo(itemResponse.getObjectNo());
|
|
itemRequest.setPlanNo(itemResponse.getPlanNo());
|
|
itemRequest.setItemId(itemResponse.getItemId());
|
|
itemRequest.setAmount(itemResponse.getAmount());
|
|
|
|
itemList.add(itemRequest);
|
|
}
|
|
|
|
// [3]. 아이템 관련 데이터 셋팅
|
|
String[] arrItemId = new String[itemList.size()];
|
|
int i = 0;
|
|
for (ItemRequest itemRequest : itemList) {
|
|
arrItemId[i++] = itemRequest.getItemId();
|
|
}
|
|
estimateRequest.setArrItemId(arrItemId);
|
|
// 아이템의 마스터 정보 및 정가 정보 조회
|
|
List<ItemResponse> itemResponseList = estimateMapper.selectItemMasterList(estimateRequest);
|
|
// BOM 정보 목록
|
|
List<ItemRequest> estimateBomList = new ArrayList<ItemRequest>();
|
|
|
|
int j = 1;
|
|
for (ItemRequest itemRequest : itemList) {
|
|
int dispOrder = 100 * j++;
|
|
itemRequest.setDispOrder(String.valueOf(dispOrder));
|
|
|
|
for (ItemResponse itemResponse : itemResponseList) {
|
|
if (itemRequest.getItemId().equals(itemResponse.getItemId())) {
|
|
itemRequest.setItemNo(itemResponse.getItemNo());
|
|
itemRequest.setItemName(itemResponse.getItemName());
|
|
itemRequest.setUnit(itemResponse.getUnit());
|
|
itemRequest.setPnowW(itemResponse.getPnowW());
|
|
itemRequest.setSpecification(itemResponse.getPnowW());
|
|
itemRequest.setUnitPrice(itemResponse.getSalePrice());
|
|
itemRequest.setSalePrice(itemResponse.getSalePrice());
|
|
itemRequest.setFileUploadFlg(itemResponse.getFileUploadFlg());
|
|
itemRequest.setPkgMaterialFlg(itemResponse.getPkgMaterialFlg());
|
|
itemRequest.setOpenFlg(itemResponse.getOpenFlg());
|
|
itemRequest.setUnitOpenFlg(itemResponse.getUnitOpenFlg());
|
|
itemRequest.setDispCableFlg("CABLE_".equals(itemResponse.getItemGroup()) ? "1" : "0");
|
|
itemRequest.setItemGroup(itemResponse.getItemGroup());
|
|
itemRequest.setItemCtgGr(itemResponse.getItemCtgGr());
|
|
itemRequest.setPartAdd("0");
|
|
itemRequest.setDelFlg("0");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 아이템 BOM Header인 경우 컴포넌트 등록 처리
|
|
if ("ERLA".equals(itemRequest.getItemCtgGr())) {
|
|
List<ItemResponse> itemBomList =
|
|
estimateMapper.selectItemMasterBomList(itemRequest.getItemId());
|
|
|
|
int k = 1;
|
|
for (ItemResponse itemResponse : itemBomList) {
|
|
ItemRequest bomItem = new ItemRequest();
|
|
|
|
bomItem.setPaDispOrder(String.valueOf(dispOrder));
|
|
bomItem.setDispOrder(String.valueOf(dispOrder + k++));
|
|
bomItem.setItemId(itemResponse.getItemId());
|
|
bomItem.setItemNo(itemResponse.getItemNo());
|
|
bomItem.setItemName(itemResponse.getItemName());
|
|
bomItem.setUnit(itemResponse.getUnit());
|
|
bomItem.setPnowW(itemResponse.getPnowW());
|
|
bomItem.setSpecification(itemResponse.getPnowW());
|
|
bomItem.setAmount(String.valueOf(Integer.parseInt(itemResponse.getBomAmount())
|
|
* Integer.parseInt(itemRequest.getAmount())));
|
|
bomItem.setBomAmount(itemResponse.getBomAmount());
|
|
bomItem.setUnitPrice(itemResponse.getSalePrice());
|
|
bomItem.setSalePrice(itemResponse.getSalePrice());
|
|
bomItem.setFileUploadFlg(itemResponse.getFileUploadFlg());
|
|
bomItem.setPkgMaterialFlg(itemResponse.getPkgMaterialFlg());
|
|
bomItem.setOpenFlg("0");
|
|
bomItem.setUnitOpenFlg("0");
|
|
bomItem.setDispCableFlg("0");
|
|
bomItem.setItemGroup(itemResponse.getItemGroup());
|
|
bomItem.setItemCtgGr(itemResponse.getItemCtgGr());
|
|
bomItem.setPartAdd("0");
|
|
bomItem.setDelFlg("0");
|
|
|
|
estimateBomList.add(bomItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
// BOM 컴포넌트 추가
|
|
itemList.addAll(estimateBomList);
|
|
|
|
// [4]. 견적특이사항 관련 데이터 셋팅
|
|
NoteRequest noteRequest = new NoteRequest();
|
|
noteRequest.setArrItemId(arrItemId);
|
|
noteRequest.setSchSpnTypeCd("COMM");
|
|
List<NoteResponse> noteList = estimateMapper.selectEstimateNoteList(noteRequest);
|
|
noteRequest.setSchSpnTypeCd("PROD");
|
|
List<NoteResponse> noteItemList = estimateMapper.selectEstimateNoteItemList(noteRequest);
|
|
|
|
// 견적특이사항 코드
|
|
String estimateOptions = "";
|
|
for (NoteResponse noteResponse : noteList) {
|
|
if ("ATTR001".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR001"; // 공통 필수체크
|
|
} else if ("ATTR002".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR002"; // YJOD 필수체크
|
|
} else if ("ATTR003".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR003"; // 출력제어시간 기본 체크
|
|
} else if ("ATTR004".equals(noteResponse.getCode())
|
|
&& "1".equals(estimateRequest.getNorthArrangement())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR004"; // 북면설치 체크
|
|
} else if ("ATTR005".equals(noteResponse.getCode())
|
|
&& "1".equals(objectResponse != null ? objectResponse.getSaltAreaFlg() : "")) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR005"; // 염해지역 체크
|
|
} else if ("ATTR006".equals(objectResponse != null ? objectResponse.getColdRegionFlg() : "")
|
|
&& "1".equals(estimateRequest.getNorthArrangement())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR006"; // 적설지역 체크
|
|
} else if ("ATTR007".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR007"; // 지붕재치수, 레이아웃 기본 체크
|
|
} else if ("ATTR008".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR008"; // 별도비용 기본 체크
|
|
} else if ("ATTR009".equals(noteResponse.getCode())) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += "ATTR009"; // 과적재 기본 체크
|
|
}
|
|
}
|
|
for (NoteResponse noteResponse : noteItemList) {
|
|
if (estimateOptions.indexOf(noteResponse.getCode()) < 0) {
|
|
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
|
|
estimateOptions += noteResponse.getCode();
|
|
}
|
|
}
|
|
estimateRequest.setEstimateOption(estimateOptions);
|
|
|
|
// 아이템별 특이사항 코드 체크
|
|
for (ItemRequest itemRequest : itemList) {
|
|
String specialNoteCd = "";
|
|
for (NoteResponse noteResponse : noteItemList) {
|
|
if (itemRequest.getItemId().equals(noteResponse.getItemId())) {
|
|
specialNoteCd += !StringUtils.isEmpty(specialNoteCd) ? splitStr : "";
|
|
specialNoteCd += noteResponse.getCode();
|
|
}
|
|
}
|
|
itemRequest.setSpecialNoteCd(specialNoteCd);
|
|
}
|
|
|
|
// 첨부파일 초기화
|
|
FileRequest fileRequest = new FileRequest();
|
|
fileRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
fileRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
fileRequest.setUserId(estimateRequest.getUserId());
|
|
fileMapper.deleteFile(fileRequest);
|
|
|
|
// 아이템 목록 필수 값 체크
|
|
BigDecimal capacity = BigDecimal.ZERO;
|
|
String moduleModel = "";
|
|
String pcTypeNo = "";
|
|
for (ItemRequest itemRequest : itemList) {
|
|
if (StringUtils.isEmpty(itemRequest.getDispOrder())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Display Order"));
|
|
}
|
|
if (StringUtils.isEmpty(itemRequest.getItemId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Item ID"));
|
|
}
|
|
if (StringUtils.isEmpty(itemRequest.getAmount())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Item Amount"));
|
|
}
|
|
|
|
// 수량
|
|
BigDecimal amount = new BigDecimal(
|
|
StringUtils.isEmpty(itemRequest.getAmount()) ? "0" : itemRequest.getAmount());
|
|
// 아이템용량
|
|
BigDecimal pnowW = new BigDecimal(
|
|
StringUtils.isEmpty(itemRequest.getPnowW()) ? "0" : itemRequest.getPnowW());
|
|
|
|
// 모듈/PC 체크
|
|
if ("MODULE_".equals(itemRequest.getItemGroup())) {
|
|
moduleModel += !StringUtils.isEmpty(moduleModel) ? splitStr : "";
|
|
moduleModel += itemRequest.getItemNo();
|
|
|
|
capacity = capacity.add(amount.multiply(pnowW));
|
|
} else if ("PC_".equals(itemRequest.getItemGroup())) {
|
|
pcTypeNo += !StringUtils.isEmpty(pcTypeNo) ? splitStr : "";
|
|
pcTypeNo += itemRequest.getItemNo();
|
|
}
|
|
}
|
|
estimateRequest.setCapacity(String.valueOf(capacity));
|
|
estimateRequest.setModuleModel(moduleModel);
|
|
estimateRequest.setPcTypeNo(pcTypeNo);
|
|
|
|
// 견적서 정보 초기화
|
|
estimateMapper.updateEstimateReset(estimateRequest);
|
|
estimateMapper.updateEstimateInfoReset(estimateRequest);
|
|
// 견적서 모든 아이템 제거
|
|
estimateMapper.deleteEstimateItemList(estimateRequest);
|
|
estimateMapper.deleteEstimateInfoItemList(estimateRequest);
|
|
|
|
// 견적서 아이템 신규 추가
|
|
String hisNo = estimateMapper.selectEstimateItemHisNo(estimateRequest); // 아이템 히스토리 번호 조회
|
|
for (ItemRequest itemRequest : itemList) {
|
|
itemRequest.setHisNo(hisNo);
|
|
itemRequest.setObjectNo(estimateRequest.getObjectNo());
|
|
itemRequest.setPlanNo(estimateRequest.getPlanNo());
|
|
itemRequest.setAmount(
|
|
!StringUtils.isEmpty(itemRequest.getAmount()) ? itemRequest.getAmount() : "0");
|
|
itemRequest.setSalePrice(
|
|
!StringUtils.isEmpty(itemRequest.getSalePrice()) ? itemRequest.getSalePrice() : "0");
|
|
itemRequest.setBomAmount(
|
|
!StringUtils.isEmpty(itemRequest.getBomAmount()) ? itemRequest.getBomAmount() : "0");
|
|
itemRequest.setPartAdd(
|
|
!StringUtils.isEmpty(itemRequest.getPartAdd()) ? itemRequest.getPartAdd() : "0");
|
|
itemRequest.setOpenFlg(
|
|
!StringUtils.isEmpty(itemRequest.getOpenFlg()) ? itemRequest.getOpenFlg() : "0");
|
|
itemRequest.setUnitOpenFlg(
|
|
!StringUtils.isEmpty(itemRequest.getUnitOpenFlg()) ? itemRequest.getUnitOpenFlg() : "0");
|
|
itemRequest.setItemChangeFlg(
|
|
!StringUtils.isEmpty(itemRequest.getItemChangeFlg()) ? itemRequest.getItemChangeFlg()
|
|
: "0");
|
|
itemRequest.setUserId(estimateRequest.getUserId());
|
|
|
|
estimateMapper.insertEstimateItemHis(itemRequest);
|
|
|
|
if (!"1".equals(itemRequest.getDelFlg())) {
|
|
estimateMapper.insertEstimateItem(itemRequest);
|
|
estimateMapper.insertEstimateInfoItem(itemRequest);
|
|
}
|
|
}
|
|
|
|
// 임시저장 상태에서는 인터페이스 막도록 처리
|
|
if ("0".equals(estimateRequest.getTempFlg())) {
|
|
// QSP Q.CAST SEND API
|
|
List<EstimateSendResponse> resultList = new ArrayList<EstimateSendResponse>();
|
|
resultList = this.sendEstimateApi(estimateRequest);
|
|
// API에서 받은 문서번호 업데이트
|
|
for (EstimateSendResponse result : resultList) {
|
|
estimateRequest.setObjectNo(result.getObjectNo());
|
|
estimateRequest.setPlanNo(result.getPlanNo());
|
|
estimateRequest.setDocNo(result.getDocNo());
|
|
estimateRequest.setSyncFlg(result.getSyncFlg());
|
|
|
|
estimateMapper.updateEstimateApi(estimateRequest);
|
|
}
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
|
|
}
|
|
|
|
// [4]. 물건번호 리턴
|
|
response.setObjectNo(estimateRequest.getObjectNo());
|
|
response.setPlanNo(estimateRequest.getPlanNo());
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* 견적서 잠금처리
|
|
*
|
|
* @param estimateRequest
|
|
* @throws Exception
|
|
*/
|
|
public void updateEstimateLock(EstimateRequest estimateRequest) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(estimateRequest.getObjectNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getPlanNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getLockFlg())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Lock Flag"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getUserId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "User ID"));
|
|
}
|
|
|
|
try {
|
|
estimateMapper.updateEstimateLock(estimateRequest);
|
|
estimateMapper.updateEstimateLastEditDate(estimateRequest);
|
|
} catch (Exception e) {
|
|
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 견적서 엑셀 다운로드
|
|
*
|
|
* @param request HttpServletRequest
|
|
* @param response HttpServletResponse
|
|
* @param estimateRequest 견적서 엑셀 다운로드 요청 정보
|
|
* @throws Exception
|
|
*/
|
|
public void excelDownload(HttpServletRequest request, HttpServletResponse response,
|
|
EstimateRequest estimateRequest) throws Exception {
|
|
|
|
EstimateResponse estimateResponse = new EstimateResponse();
|
|
String splitStr = "、";
|
|
|
|
// Validation
|
|
if (StringUtils.isEmpty(estimateRequest.getObjectNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getPlanNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
|
|
try {
|
|
|
|
// 견적서 상세 조회
|
|
estimateResponse = estimateMapper.selectEstimatePdfDetail(estimateRequest);
|
|
|
|
// 1차점이 2차점 견적서를 만들어 준 경우 - 2차점 사용자가 다운받을 시 무조건 정가로만 표시
|
|
String userId = estimateRequest.getUserId();
|
|
String storeLvl = estimateRequest.getStoreLvl();
|
|
if (storeLvl != null && !storeLvl.equals("1")) {
|
|
if (!Objects.equals(estimateResponse.getCreateSaleStoreId(), userId)) {
|
|
estimateRequest.setSchUnitPriceFlg("1");
|
|
}
|
|
}
|
|
|
|
// file Name 명이 없는경우
|
|
if (estimateRequest.getFileName() == null || "".equals(estimateRequest.getFileName())) {
|
|
estimateRequest.setFileName(StringUtils.defaultString(estimateResponse.getObjectNo()) + "_"
|
|
+ StringUtils.defaultString(estimateResponse.getPlanNo()) + "_"
|
|
+ new SimpleDateFormat("yyyyMMdd").format(new Date()));
|
|
}
|
|
|
|
if ("1".equals(estimateRequest.getSchDisplayFlg())) {
|
|
estimateResponse.setCustSaleStoreName(estimateResponse.getObjectName());
|
|
estimateResponse.setCustOmit(estimateResponse.getObjectNameOmit());
|
|
} else {
|
|
estimateResponse.setCustOmit("様邸");
|
|
}
|
|
|
|
// 견적서 잠금 처리 (최종 수정일 업데이트)
|
|
estimateRequest.setLockFlg("1");
|
|
estimateMapper.updateEstimateLock(estimateRequest);
|
|
estimateMapper.updateEstimateLastEditDate(estimateRequest);
|
|
|
|
// 견적서 특이사항 조회
|
|
List<NoteResponse> noteList = new ArrayList<NoteResponse>();
|
|
if (!StringUtils.isEmpty(estimateResponse.getEstimateOption())) {
|
|
String[] arrSpnAttrCd =
|
|
new String[estimateResponse.getEstimateOption().split(splitStr).length];
|
|
int i = 0;
|
|
for (String str : estimateResponse.getEstimateOption().split(splitStr)) {
|
|
arrSpnAttrCd[i++] = str;
|
|
}
|
|
|
|
NoteRequest noteRequest = new NoteRequest();
|
|
noteRequest.setArrSpnAttrCd(arrSpnAttrCd);
|
|
noteList = estimateMapper.selectEstimateNoteList(noteRequest);
|
|
|
|
estimateResponse.setNoteList(noteList);
|
|
}
|
|
|
|
// 지붕면 목록 조회
|
|
RoofInfoResponse roofInfoResponse = new RoofInfoResponse();
|
|
List<RoofResponse> roofList = estimateMapper.selectEstimateRoofList(estimateRequest);
|
|
List<ItemResponse> circuitItemList =
|
|
estimateMapper.selectEstimateCircuitItemList(estimateRequest);
|
|
estimateRequest.setSchItemGroup("MODULE_");
|
|
List<RoofResponse> roofVolList = estimateMapper.selectEstimateRoofVolList(estimateRequest);
|
|
|
|
BigDecimal moduleTotAmount = BigDecimal.ZERO;
|
|
BigDecimal moduleTotVolKw = BigDecimal.ZERO;
|
|
for (RoofResponse roofVol : roofVolList) {
|
|
BigDecimal amount =
|
|
new BigDecimal(StringUtils.isEmpty(roofVol.getAmount()) ? "0" : roofVol.getAmount());
|
|
BigDecimal vol =
|
|
new BigDecimal(StringUtils.isEmpty(roofVol.getVolKw()) ? "0" : roofVol.getVolKw());
|
|
|
|
String classTypeName = "";
|
|
if ("0".equals(roofVol.getClassType())) {
|
|
classTypeName = new BigDecimal(StringUtils.defaultString(roofVol.getSlope(), "0")).stripTrailingZeros().toPlainString() + "寸";
|
|
} else {
|
|
classTypeName = new BigDecimal(StringUtils.defaultString(roofVol.getAngle(), "0")).stripTrailingZeros().toPlainString() + "º";
|
|
}
|
|
roofVol.setClassTypeName(classTypeName);
|
|
|
|
moduleTotAmount = moduleTotAmount.add(amount);
|
|
moduleTotVolKw = moduleTotVolKw.add(vol);
|
|
}
|
|
roofInfoResponse.setModuleTotAmount(String.valueOf(moduleTotAmount));
|
|
roofInfoResponse.setModuleTotVolKw(String.valueOf(moduleTotVolKw));
|
|
|
|
for (RoofResponse roof : roofList) {
|
|
String roofClassTypeName = "";
|
|
if ("0".equals(roof.getClassType())) {
|
|
roofClassTypeName = new BigDecimal(StringUtils.defaultString(roof.getSlope(), "0")).stripTrailingZeros().toPlainString() + "寸";
|
|
} else {
|
|
roofClassTypeName = new BigDecimal(StringUtils.defaultString(roof.getAngle(), "0")).stripTrailingZeros().toPlainString() + "º";
|
|
}
|
|
roof.setClassTypeName(roofClassTypeName);
|
|
}
|
|
roofInfoResponse.setRoofList(roofList);
|
|
roofInfoResponse.setCircuitItemList(circuitItemList);
|
|
roofInfoResponse.setRoofVolList(roofVolList);
|
|
|
|
// 인증용량 구하기 (지붕면마다 모듈과 각각의 PCS의 총 용량을 서로 비교해 낮은쪽 용량으로 합산)
|
|
roofInfoResponse.setCertVolKw(estimateMapper.selectEstimateRoofCertVolKw(estimateRequest));
|
|
|
|
//방위값
|
|
CanvasPopupStatus cps = canvasPopupStatusService.selectCanvasPopupStatus(estimateResponse.getObjectNo(), Integer.parseInt(estimateResponse.getPlanNo()), "1");
|
|
String popupStatus = cps.getPopupStatus();
|
|
ExcelUtil excelUtil = new ExcelUtil();
|
|
try {
|
|
com.fasterxml.jackson.databind.ObjectMapper jsonMapper =
|
|
new com.fasterxml.jackson.databind.ObjectMapper();
|
|
com.fasterxml.jackson.databind.JsonNode jsonNode = jsonMapper.readTree(popupStatus);
|
|
|
|
// 특정 키의 값을 가져오기
|
|
String compasDeg = jsonNode.get("compasDeg").toString();
|
|
double degreeValue = Double.parseDouble(compasDeg.replace("\"", ""));
|
|
|
|
// 각도 매핑 함수 호출
|
|
String mappedDegree = excelUtil.mapCompassDegree(degreeValue);
|
|
|
|
|
|
try {
|
|
// classpath에서 리소스 파일을 읽어옵니다
|
|
String imagePath = "/img/compass/" + mappedDegree + ".png";
|
|
InputStream imageInputStream = getClass().getResourceAsStream(imagePath);
|
|
|
|
if (imageInputStream != null) {
|
|
byte[] degImg = imageInputStream.readAllBytes();
|
|
roofInfoResponse.setCompasDegImg(degImg);
|
|
imageInputStream.close();
|
|
} else {
|
|
log.warn("Compass image not found: {}", imagePath);
|
|
}
|
|
} catch (IOException e) {
|
|
log.error("Error reading compass image: {}", e.getMessage(), e);
|
|
}
|
|
|
|
roofInfoResponse.setCompasDeg(compasDeg);
|
|
|
|
|
|
} catch (Exception e) {
|
|
log.error("JSON 파싱 오류: ", e);
|
|
}
|
|
|
|
|
|
estimateResponse.setRoofInfo(roofInfoResponse);
|
|
|
|
// 아이템 목록 조회
|
|
List<ItemResponse> estimateItemList = estimateMapper.selectEstimateItemList(estimateRequest);
|
|
|
|
// 총 합산금액 계산
|
|
this.selectTotalPriceInfo(estimateResponse, estimateItemList,
|
|
estimateRequest.getSchUnitPriceFlg());
|
|
|
|
boolean isPdfDownload = "PDF".equals(estimateRequest.getSchDownload());
|
|
int j = 1;
|
|
for (ItemResponse itemResponse : estimateItemList) {
|
|
itemResponse.setNo(String.valueOf(j++));
|
|
|
|
// itemName 디코딩 및 HTML Unescape 처리
|
|
String itemName = itemResponse.getItemName();
|
|
if (StringUtils.isNotEmpty(itemName)) {
|
|
try {
|
|
// 1. URL 디코딩 (% 처리)
|
|
if (itemName.contains("%")) {
|
|
itemName = URLDecoder.decode(itemName, StandardCharsets.UTF_8);
|
|
}
|
|
|
|
// 2. HTML Unescape 처리 (&가 포함된 경우만)
|
|
// &amp;Phi;1 -> &Phi;1 -> Φ1 순차적으로 복원
|
|
if (itemName.contains("&")) {
|
|
String prevName;
|
|
do {
|
|
prevName = itemName;
|
|
itemName = HtmlUtils.htmlUnescape(itemName);
|
|
} while (!prevName.equals(itemName) && itemName.contains("&"));
|
|
}
|
|
|
|
itemResponse.setItemName(itemName);
|
|
} catch (Exception e) {
|
|
log.warn("Excel itemName processing failed: {}", itemName);
|
|
}
|
|
}
|
|
|
|
// 문자열 통화로 변환 처리 (PDF 전용)
|
|
if (isPdfDownload) {
|
|
itemResponse.setSalePrice(
|
|
String.format("%1$,.0f", Double.parseDouble(itemResponse.getSalePrice())));
|
|
itemResponse.setAmount(
|
|
String.format("%1$,.0f", Double.parseDouble(itemResponse.getAmount())));
|
|
itemResponse.setSaleTotPrice(
|
|
String.format("%1$,.0f", Double.parseDouble(itemResponse.getSaleTotPrice())));
|
|
}
|
|
|
|
if ("YJSS".equals(estimateResponse.getEstimateType())
|
|
&& (!StringUtils.isEmpty(itemResponse.getPaDispOrder())
|
|
|| !"1".equals(itemResponse.getPkgMaterialFlg()))) {
|
|
itemResponse.setSalePrice("");
|
|
itemResponse.setSaleTotPrice("");
|
|
}
|
|
|
|
// 886 Excel, PDF에 OPEN_FLG = 1은 단가필드에 OPEN 텍스트로 보여주도록
|
|
if ("1".equals(itemResponse.getOpenFlg())) {
|
|
itemResponse.setSalePrice("OPEN");
|
|
itemResponse.setSaleTotPrice("OPEN");
|
|
}
|
|
|
|
String nullChk = StringUtils.isEmpty(itemResponse.getSalePrice()) ? "0" : itemResponse.getSalePrice();
|
|
if ("1".equals(itemResponse.getUnitOpenFlg()) && "1".equals(estimateRequest.getSchUnitPriceFlg())){
|
|
|
|
itemResponse.setSalePrice("OPEN");
|
|
itemResponse.setSaleTotPrice("OPEN");
|
|
|
|
}
|
|
}
|
|
|
|
// 합산 문자열 통화로 변환 처리
|
|
estimateResponse.setPkgYn("YJSS".equals(estimateResponse.getEstimateType()) ? "Y" : "N");
|
|
estimateResponse
|
|
.setPkgNo("YJSS".equals(estimateResponse.getEstimateType()) ? String.valueOf(j++) : "");
|
|
if (isPdfDownload) {
|
|
if ("YJSS".equals(estimateResponse.getEstimateType())) {
|
|
estimateResponse.setPkgAsp(
|
|
String.format("%1$,.0f", Double.parseDouble(estimateResponse.getPkgAsp())));
|
|
}
|
|
estimateResponse.setTotVol(
|
|
String.format("%1$,.0f", Double.parseDouble(estimateResponse.getTotVol())));
|
|
estimateResponse.setPkgTotPrice(
|
|
String.format("%1$,.0f", Double.parseDouble(estimateResponse.getPkgTotPrice())));
|
|
estimateResponse.setSupplyPrice(
|
|
String.format("%1$,.0f", Double.parseDouble(estimateResponse.getSupplyPrice())));
|
|
estimateResponse.setVatPrice(
|
|
String.format("%1$,.0f", Double.parseDouble(estimateResponse.getVatPrice())));
|
|
estimateResponse.setTotPrice(
|
|
String.format("%1$,.0f", Double.parseDouble(estimateResponse.getTotPrice())));
|
|
}
|
|
|
|
// 발전시뮬레이션 계산
|
|
PwrGnrSimRequest pwrGnrSimRequest = new PwrGnrSimRequest();
|
|
pwrGnrSimRequest.setObjectNo(estimateResponse.getObjectNo());
|
|
pwrGnrSimRequest.setPlanNo(estimateResponse.getPlanNo());
|
|
|
|
PwrGnrSimResponse pwrGnrSimResponse =
|
|
pwrGnrSimService.selectPwrGnrSimulation(pwrGnrSimRequest);
|
|
pwrGnrSimResponse.setPwrGnrSimType(estimateRequest.getPwrGnrSimType());
|
|
|
|
// 발전시뮬레이션 타입에 따른 list 셋팅
|
|
if ("A".equals(estimateRequest.getPwrGnrSimType())) {
|
|
pwrGnrSimResponse.setFrcPwrGnrList(pwrGnrSimResponse.getHatsudenryouAll());
|
|
} else if ("B".equals(estimateRequest.getPwrGnrSimType())) {
|
|
pwrGnrSimResponse.setFrcPwrGnrList(pwrGnrSimResponse.getHatsudenryouAllSnow());
|
|
} else if ("C".equals(estimateRequest.getPwrGnrSimType())) {
|
|
pwrGnrSimResponse.setFrcPwrGnrList(pwrGnrSimResponse.getHatsudenryouPeakcutAll());
|
|
} else if ("D".equals(estimateRequest.getPwrGnrSimType())) {
|
|
pwrGnrSimResponse.setFrcPwrGnrList(pwrGnrSimResponse.getHatsudenryouPeakcutAllSnow());
|
|
}
|
|
|
|
pwrGnrSimResponse.setIntFrcPwrGnrList(
|
|
Arrays.stream(pwrGnrSimResponse.getFrcPwrGnrList()).map(s -> s.replace(",", "")) // , 제거
|
|
.mapToInt(Integer::parseInt) // 문자열을 int로 변환
|
|
.toArray());
|
|
|
|
if (pwrGnrSimResponse != null) {
|
|
try {
|
|
// 발전시뮬레이션 안내사항 조회
|
|
PwrGnrSimGuideResponse pwrGnrSimGuideInfo =
|
|
pwrGnrSimService.selectPwrGnrSimulationGuideInfo();
|
|
if (pwrGnrSimGuideInfo != null) {
|
|
pwrGnrSimResponse.setGuideInfo(pwrGnrSimGuideInfo.getData());
|
|
}
|
|
} catch (Exception e) {
|
|
log.error(e.toString());
|
|
}
|
|
}
|
|
|
|
estimateResponse.setPwrGnrSim(pwrGnrSimResponse);
|
|
|
|
// 도면 이미지 셋팅
|
|
String baseDrawingImgName = estimateRequest.getObjectNo() + "_" + estimateRequest.getPlanNo();
|
|
|
|
// 셀범위용 이미지 (기존 이미지명 유지: _1.png, _2.png)
|
|
URL url = new URL(drawingDirPath + File.separator + baseDrawingImgName + "_1.png");
|
|
byte[] drawingImg1 = loadDrawingImage(url);
|
|
if (drawingImg1 != null) {
|
|
estimateResponse.setDrawingImg1(drawingImg1);
|
|
}
|
|
log.debug("url1 ::: {}", url);
|
|
|
|
URL url2 = new URL(drawingDirPath + File.separator + baseDrawingImgName + "_2.png");
|
|
byte[] drawingImg2 = loadDrawingImage(url2);
|
|
if (drawingImg2 != null) {
|
|
estimateResponse.setDrawingImg2(drawingImg2);
|
|
}
|
|
log.debug("url2 ::: {}", url2);
|
|
|
|
// 풀사이즈 이미지 (P1, P2 시트용: _1_full.png, _2_full.png)
|
|
URL urlFull1 = new URL(drawingDirPath + File.separator + baseDrawingImgName + "_1_full.png");
|
|
byte[] drawingImg1Full = loadDrawingImage(urlFull1);
|
|
if (drawingImg1Full != null) {
|
|
estimateResponse.setDrawingImg1Full(drawingImg1Full);
|
|
} else {
|
|
// full 이미지가 없으면 기존 이미지로 폴백
|
|
estimateResponse.setDrawingImg1Full(drawingImg1);
|
|
}
|
|
|
|
URL urlFull2 = new URL(drawingDirPath + File.separator + baseDrawingImgName + "_2_full.png");
|
|
byte[] drawingImg2Full = loadDrawingImage(urlFull2);
|
|
if (drawingImg2Full != null) {
|
|
estimateResponse.setDrawingImg2Full(drawingImg2Full);
|
|
} else {
|
|
estimateResponse.setDrawingImg2Full(drawingImg2);
|
|
}
|
|
|
|
|
|
//userId 에 따른 영업점 주소, 전화, fax 정보 조회
|
|
if(estimateRequest.getSaleStoreId() != null && "T01".equals(estimateRequest.getSaleStoreId())){
|
|
|
|
String strResponse = interfaceQsp.callApi(HttpMethod.GET,
|
|
QSP_API_URL + "/api/admin/userDetail?loginId="+estimateRequest.getUserId(), null);
|
|
|
|
if (!"".equals(strResponse)) {
|
|
com.fasterxml.jackson.databind.ObjectMapper om =
|
|
new com.fasterxml.jackson.databind.ObjectMapper()
|
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
EstimateApiResponse estimateApiResponse = om.readValue(strResponse, EstimateApiResponse.class);
|
|
|
|
// API 응답 데이터 존재 여부 확인 및 안전한 데이터 추출
|
|
if (estimateApiResponse != null && estimateApiResponse.getData() != null) {
|
|
try {
|
|
// API 응답 데이터를 Map으로 변환하여 필요한 정보 추출
|
|
@SuppressWarnings("unchecked")
|
|
Map<String, Object> userData = (Map<String, Object>) estimateApiResponse.getData();
|
|
|
|
if (!userData.isEmpty()) {
|
|
//영업점 주소 확인 및 설정
|
|
Object salesOfficeAddr = userData.get("salesOfficeAddr");
|
|
if (salesOfficeAddr != null &&
|
|
!StringUtils.isEmpty(salesOfficeAddr.toString().trim())) {
|
|
estimateResponse.setZipNo("");
|
|
estimateResponse.setAddress(salesOfficeAddr.toString().replaceAll("\n", "<br>"));
|
|
}
|
|
|
|
//영업점 전화 확인 및 설정
|
|
Object salesOfficeTel = userData.get("salesOfficeTel");
|
|
if (salesOfficeTel != null &&
|
|
!StringUtils.isEmpty(salesOfficeTel.toString().trim())) {
|
|
estimateResponse.setTel(salesOfficeTel.toString());
|
|
}
|
|
|
|
//영업점 팩스 확인 및 설정
|
|
Object salesOfficeFax = userData.get("salesOfficeFax");
|
|
if (salesOfficeFax != null &&
|
|
!StringUtils.isEmpty(salesOfficeFax.toString().trim())) {
|
|
estimateResponse.setFax(salesOfficeFax.toString());
|
|
}
|
|
}
|
|
} catch (ClassCastException e) {
|
|
log.warn("API 응답 데이터 형변환 실패: {}", e.getMessage());
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
log.warn("common.message.required.data", "User Detail");
|
|
}
|
|
}
|
|
|
|
if ("PDF".equals(estimateRequest.getSchDownload())) { // PDF 다운로드
|
|
String[] arrSection = new String[6];
|
|
int iSection = 0;
|
|
|
|
String templateFilePath = "pdf_download_quotation_detail_template.html";
|
|
|
|
|
|
// 템플릿 html 조회
|
|
Document doc = PdfUtil.getPdfDoc(request, templateFilePath);
|
|
|
|
// 견적서 상세 pdf Html 생성
|
|
doc = this.estimatePdfHtml(doc, estimateResponse, estimateItemList);
|
|
|
|
// 발전시뮬레이션 pdf Html 생성
|
|
doc = pwrGnrSimService.pwrGnrSimPdfHtml(doc, pwrGnrSimResponse);
|
|
|
|
// SchDrawingFlg (1 : 견적서,2 : 발전시뮬레이션, 3 : 도면, 4 : 가대)
|
|
// ex) 1|2|3|4
|
|
if (!StringUtils.isEmpty(estimateRequest.getSchDrawingFlg())) {
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("1") > -1) {
|
|
arrSection[iSection] = "div.section1";
|
|
iSection++;
|
|
arrSection[iSection] = "div.section2";
|
|
iSection++;
|
|
}
|
|
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("2") > -1) {
|
|
arrSection[iSection] = "div.section3"; // 발전시뮬레이션
|
|
iSection++;
|
|
}
|
|
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("3") > -1) {
|
|
arrSection[iSection] = "div.section4"; // 도면
|
|
iSection++;
|
|
arrSection[iSection] = "div.section5"; // 도면
|
|
iSection++;
|
|
}
|
|
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("4") > -1) {
|
|
arrSection[iSection] = "div.section6";
|
|
iSection++;
|
|
}
|
|
}
|
|
|
|
// 섹션별 방향 설정 (이미지가 들어가는 섹션은 가로)
|
|
java.util.Map<String, Boolean> sectionOrientation = new java.util.HashMap<>();
|
|
sectionOrientation.put("div.section3", true); // 발전시뮬레이션 - 가로
|
|
sectionOrientation.put("div.section4", true); // 도면 - 가로
|
|
sectionOrientation.put("div.section5", true); // 도면 - 가로
|
|
|
|
// pdf 다운로드
|
|
PdfUtil.pdfDownload(request, response, doc, estimateRequest.getFileName(), arrSection, false, sectionOrientation);
|
|
|
|
} else {
|
|
|
|
Workbook workbook = null;
|
|
|
|
String excelTemplateNam = "excel_download_quotation_detail_template.xlsx";
|
|
|
|
// itemGroup이 "STAND_"가 아닌 항목들만 필터링하여 새로운 리스트 생성
|
|
List<ItemResponse> estimateItemList15 = estimateItemList.stream()
|
|
.filter(item -> !"STAND_".equals(item.getItemGroup()))
|
|
.collect(Collectors.toList());
|
|
|
|
// itemGroup이 "STAND_"인 항목들만 필터링하여 새로운 리스트 생성
|
|
List<ItemResponse> estimateItemListS15 = estimateItemList.stream()
|
|
.filter(item -> "STAND_".equals(item.getItemGroup()))
|
|
.collect(Collectors.toList());
|
|
|
|
if(estimateItemListS15.size() < 16) {
|
|
// 15개 미만인 경우, 나머지 아이템을 빈 값으로 채움
|
|
for (int k = estimateItemListS15.size(); k < 15; k++) {
|
|
ItemResponse emptyItem = new ItemResponse();
|
|
estimateItemListS15.add(emptyItem);
|
|
}
|
|
}else {
|
|
// 15개 이상인 경우, 15개로 자름
|
|
estimateItemListS15 = estimateItemListS15.subList(0, 14);
|
|
}
|
|
|
|
estimateResponse.setEstimateItemListS15(estimateItemListS15);
|
|
|
|
|
|
|
|
if(estimateItemList15.size() < 16) {
|
|
// 15개 미만인 경우, 나머지 아이템을 빈 값으로 채움
|
|
for (int k = estimateItemList15.size(); k < 15; k++) {
|
|
ItemResponse emptyItem = new ItemResponse();
|
|
emptyItem.setNo(String.valueOf(k + 1));
|
|
estimateItemList15.add(emptyItem);
|
|
}
|
|
}else {
|
|
// 15개 이상인 경우, 15개로 자름
|
|
estimateItemList15 = estimateItemList15.subList(0, 14);
|
|
}
|
|
|
|
estimateResponse.setEstimateItemList15(estimateItemList15);
|
|
|
|
|
|
List<ItemResponse> circuitItemList11 = estimateResponse.getRoofInfo().getCircuitItemList();
|
|
|
|
if (circuitItemList11 != null && circuitItemList11.size() < 12){
|
|
// 12개 미만인 경우, 나머지 아이템을 빈 값으로 채움
|
|
for (int k = circuitItemList11.size(); k < 11; k++) {
|
|
ItemResponse emptyItem = new ItemResponse();
|
|
circuitItemList11.add(emptyItem);
|
|
}
|
|
}else {
|
|
// 12개 이상인 경우, 12개로 자름
|
|
circuitItemList11 = circuitItemList11.subList(0, 11);
|
|
}
|
|
estimateResponse.setCircuitItemList11(circuitItemList11);
|
|
|
|
// 지붕면 목록에서 8개로 자름
|
|
List<PwrGnrSimRoofResponse> roofModuleList8 = estimateResponse.getPwrGnrSim().getRoofModuleList();
|
|
|
|
if (roofModuleList8 != null && roofModuleList8.size() < 9) {
|
|
// 9개 미만인 경우, 나머지 아이템을 빈 값으로 채움
|
|
for (int k = roofModuleList8.size(); k < 8; k++) {
|
|
PwrGnrSimRoofResponse emptyRoof = new PwrGnrSimRoofResponse();
|
|
roofModuleList8.add(emptyRoof);
|
|
}
|
|
}else {
|
|
// 9개 이상인 경우, 9개로 자름
|
|
roofModuleList8 = roofModuleList8.subList(0, 8);
|
|
}
|
|
estimateResponse.setRoofModuleList8(roofModuleList8);
|
|
|
|
//pcs list 3개
|
|
List<PwrGnrSimRoofResponse> pcsList3 = estimateResponse.getPwrGnrSim().getPcsList();
|
|
if (pcsList3 != null && pcsList3.size() < 4) {
|
|
// 4개 미만인 경우, 나머지 아이템을 빈 값으로 채움
|
|
for (int k = pcsList3.size(); k < 4; k++) {
|
|
PwrGnrSimRoofResponse emptyPcs = new PwrGnrSimRoofResponse();
|
|
pcsList3.add(emptyPcs);
|
|
}
|
|
|
|
} else {
|
|
// 4개 이상인 경우, 4개로 자름
|
|
pcsList3 = pcsList3.subList(0, 3);
|
|
|
|
}
|
|
estimateResponse.setPcsList3(pcsList3);
|
|
|
|
excelUtil = new ExcelUtil();
|
|
Map<String, Object> excelData = excelUtil.convertVoToMap(estimateResponse);
|
|
List<Map<String, Object>> excelList = excelUtil.convertListToMap(estimateItemList);
|
|
coerceExcelDataNumberFields(excelData);
|
|
coerceExcelItemNumberFields(excelList);
|
|
putExcelItemList(excelData, "itemList", estimateResponse.getItemList());
|
|
putExcelItemList(excelData, "estimateItemList15", estimateResponse.getEstimateItemList15());
|
|
putExcelItemList(excelData, "estimateItemListS15", estimateResponse.getEstimateItemListS15());
|
|
putExcelItemList(excelData, "circuitItemList11", estimateResponse.getCircuitItemList11());
|
|
putExcelRoofList(excelData, "roofModuleList8", estimateResponse.getRoofModuleList8());
|
|
putExcelRoofList(excelData, "pcsList3", estimateResponse.getPcsList3());
|
|
byte[] excelBytes =
|
|
excelUtil.download(request, response, excelData, excelList, excelTemplateNam);
|
|
|
|
if (excelBytes == null || excelBytes.length == 0) {
|
|
throw new RuntimeException("Excel template processing returned empty result. Template: " + excelTemplateNam);
|
|
}
|
|
|
|
InputStream in = new ByteArrayInputStream(excelBytes);
|
|
workbook = WorkbookFactory.create(in); // JXLS POI 엑셀로 재변환
|
|
|
|
// 이미지 가로세로 비율 보정
|
|
adjustImageAspectRatio(workbook);
|
|
|
|
// SchDrawingFlg (1 : 견적서,2 : 발전시뮬레이션, 3 : 도면, 4 : 가대)
|
|
// ex) 1|2|3|4
|
|
if (!StringUtils.isEmpty(estimateRequest.getSchDrawingFlg())) {
|
|
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("1") < 0) {
|
|
safeRemoveSheet(workbook, "見積書");
|
|
safeRemoveSheet(workbook, "特異事項");
|
|
|
|
}
|
|
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("2") < 0) {
|
|
safeRemoveSheet(workbook, "発電シミュレーション");
|
|
|
|
}
|
|
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("3") < 0) {
|
|
safeRemoveSheet(workbook, "割付図・系統図");
|
|
safeRemoveSheet(workbook, "架台図");
|
|
safeRemoveSheet(workbook, "P1");
|
|
safeRemoveSheet(workbook, "P2");
|
|
|
|
}
|
|
|
|
safeRemoveSheet(workbook, "特異事項");
|
|
}
|
|
|
|
// 추후 개발 (가대중량표)
|
|
if (estimateRequest.getSchDrawingFlg().indexOf("4") < 0) {
|
|
safeRemoveSheet(workbook, "重量算出シート");
|
|
safeRemoveSheet(workbook, "特異事項");
|
|
}
|
|
|
|
// 2026-05-06 신/구 견적서 양식에 따른 견적서 시트만 교체.
|
|
// schDrawingFlg / schWeightFlg(위쪽 분기)로 선택된 부속 시트
|
|
// (割付図・系統図 / 架台図 / 発電シミュレーション / 重量算出シート 등)는 그대로 유지한다.
|
|
if ("EXCEL2".equals(estimateRequest.getSchDownload())) {
|
|
// 旧見積書書式: 신 양식 견적서 시트(見積書) 제거 후, 구 양식(御見積書)을 맨 앞으로 이동
|
|
// 2026-06-01 시트명 변경: 見積書. → 御見積書
|
|
safeRemoveSheet(workbook, "見積書");
|
|
if (workbook.getSheetIndex("御見積書") > 0) {
|
|
workbook.setSheetOrder("御見積書", 0);
|
|
}
|
|
} else {
|
|
// 신(통상) 견적서 양식: 구 양식 견적서 시트(御見積書)만 제거
|
|
safeRemoveSheet(workbook, "御見積書");
|
|
}
|
|
safeRemoveSheet(workbook, "特異事項");
|
|
|
|
applyExcelNumberFormat(workbook);
|
|
// applyExcelFixedNumberFormat(workbook, Arrays.asList("H25", "C12"), "#,##0.00");
|
|
// applyExcelFixedNumberFormat(workbook, Arrays.asList("X32", "I44"), "#,##0.00");
|
|
|
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
workbook.write(byteArrayOutputStream);
|
|
excelBytes = byteArrayOutputStream.toByteArray();
|
|
|
|
response.setHeader("Content-Disposition",
|
|
"attachment; filename=\"" + estimateRequest.getFileName() + ".xlsx\"");
|
|
response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
|
|
response.getOutputStream().write(excelBytes);
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
log.error("Failed to excelDownload estimate. Request: {}", request, e);
|
|
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 아이템 목록을 통한 견적서 가격 자동계산
|
|
*
|
|
* @param estimateResponse 견적서 정보
|
|
* @param itemList 아이템 정보 목록
|
|
* @param unitPriceFlg 가격 표시 코드
|
|
* @throws Exception
|
|
*/
|
|
public void selectTotalPriceInfo(EstimateResponse estimateResponse, List<ItemResponse> itemList,
|
|
String unitPriceFlg) throws Exception {
|
|
BigDecimal totAmount = BigDecimal.ZERO;
|
|
BigDecimal totVol = BigDecimal.ZERO;
|
|
BigDecimal pkgTotPrice = BigDecimal.ZERO;
|
|
BigDecimal supplyPrice = BigDecimal.ZERO;
|
|
BigDecimal vatPrice = BigDecimal.ZERO;
|
|
BigDecimal totPrice = BigDecimal.ZERO;
|
|
|
|
String estimateType = estimateResponse.getEstimateType();
|
|
|
|
// 주택패키지 단가
|
|
BigDecimal pkgAsp = new BigDecimal(
|
|
StringUtils.isEmpty(estimateResponse.getPkgAsp()) ? "0" : estimateResponse.getPkgAsp());
|
|
|
|
for (ItemResponse itemResponse : itemList) {
|
|
// 수량
|
|
BigDecimal amount = new BigDecimal(
|
|
StringUtils.isEmpty(itemResponse.getAmount()) ? "0" : itemResponse.getAmount());
|
|
// 판매가
|
|
BigDecimal salePrice = BigDecimal.ZERO;
|
|
if ("1".equals(unitPriceFlg)) {
|
|
salePrice = new BigDecimal(
|
|
StringUtils.isEmpty(itemResponse.getUnitPrice()) ? "0" : itemResponse.getUnitPrice());
|
|
|
|
itemResponse.setSalePrice(String.valueOf(salePrice));
|
|
} else {
|
|
salePrice = new BigDecimal(
|
|
StringUtils.isEmpty(itemResponse.getSalePrice()) ? "0" : itemResponse.getSalePrice());
|
|
}
|
|
// 아이템용량
|
|
BigDecimal pnowW = new BigDecimal(
|
|
StringUtils.isEmpty(itemResponse.getPnowW()) ? "0" : itemResponse.getPnowW());
|
|
|
|
// 아이템 단가 합산
|
|
itemResponse.setSaleTotPrice(String.valueOf(salePrice.multiply(amount)));
|
|
|
|
// 컴포넌트는 제외하고 계산
|
|
if (StringUtils.isEmpty(itemResponse.getPaDispOrder())) {
|
|
// YJSS인 경우 (PKG 단가 * 모듈용량) + 패키지 제외상품 총 합산
|
|
// YJOD인 경우 모든 아이템의 총 합산
|
|
if ("YJSS".equals(estimateType)) {
|
|
if ("1".equals(itemResponse.getModuleFlg())) {
|
|
totVol = totVol.add(pnowW.multiply(amount));
|
|
}
|
|
|
|
if ("1".equals(itemResponse.getPkgMaterialFlg())) { // 패키지 제외상품 여부(1)
|
|
supplyPrice = supplyPrice.add(salePrice.multiply(amount));
|
|
}
|
|
} else {
|
|
if ("1".equals(itemResponse.getModuleFlg())) {
|
|
totVol = totVol.add(pnowW.multiply(amount));
|
|
}
|
|
|
|
supplyPrice = supplyPrice.add(salePrice.multiply(amount));
|
|
}
|
|
}
|
|
|
|
// 주문수량 더하기
|
|
totAmount = totAmount.add(amount);
|
|
}
|
|
|
|
if ("YJSS".equals(estimateType)) {
|
|
pkgTotPrice = pkgAsp.multiply(totVol);
|
|
pkgTotPrice = pkgTotPrice.setScale(0, RoundingMode.HALF_UP);
|
|
supplyPrice = supplyPrice.add(pkgTotPrice);
|
|
}
|
|
|
|
// 부가세 계산 (10프로)
|
|
vatPrice = supplyPrice.multiply(new BigDecimal("0.1"));
|
|
// 총 가격 합산 (공급가 + 부가세)
|
|
totPrice = totPrice.add(supplyPrice.add(vatPrice));
|
|
|
|
estimateResponse.setPkgTotPrice(String.valueOf(pkgTotPrice));
|
|
estimateResponse.setTotAmount(String.valueOf(totAmount.setScale(0, RoundingMode.HALF_UP)));
|
|
estimateResponse.setTotVol(String.valueOf(totVol));
|
|
estimateResponse.setTotVolKw(String
|
|
.valueOf(totVol.multiply(new BigDecimal("0.001")).setScale(3, RoundingMode.FLOOR)));
|
|
estimateResponse
|
|
.setSupplyPrice(String.valueOf(supplyPrice.setScale(0, RoundingMode.HALF_UP)));
|
|
estimateResponse.setVatPrice(String.valueOf(vatPrice.setScale(0, RoundingMode.HALF_UP)));
|
|
estimateResponse.setTotPrice(String.valueOf(totPrice.setScale(0, RoundingMode.HALF_UP)));
|
|
}
|
|
|
|
private static final Set<String> EXCEL_ITEM_NUMBER_FIELDS = new HashSet<>(
|
|
Arrays.asList("amount", "bomAmount", "salePrice", "unitPrice", "saleTotPrice", "grossWt", "pnowW"));
|
|
|
|
private static final Set<String> EXCEL_DATA_NUMBER_FIELDS = new HashSet<>(
|
|
Arrays.asList("pkgAsp", "totAmount", "totVol", "totVolKw", "pkgTotPrice",
|
|
"supplyPrice", "vatPrice", "totPrice"));
|
|
|
|
private static final Set<String> EXCEL_ROOF_NUMBER_FIELDS = new HashSet<>(
|
|
Arrays.asList("amount", "totSpecification", "specification", "cnvEff",
|
|
"amp", "tempLoss", "tempCoeff"));
|
|
|
|
private static void coerceExcelItemNumberFields(List<Map<String, Object>> list) {
|
|
if (list == null) {
|
|
return;
|
|
}
|
|
for (Map<String, Object> row : list) {
|
|
coerceExcelNumberFields(row, EXCEL_ITEM_NUMBER_FIELDS);
|
|
}
|
|
}
|
|
|
|
private static void coerceExcelDataNumberFields(Map<String, Object> map) {
|
|
coerceExcelNumberFields(map, EXCEL_DATA_NUMBER_FIELDS);
|
|
coerceExcelScale(map, "totVol", 2);
|
|
}
|
|
|
|
private static void coerceExcelRoofNumberFields(List<Map<String, Object>> list) {
|
|
if (list == null) {
|
|
return;
|
|
}
|
|
for (Map<String, Object> row : list) {
|
|
coerceExcelNumberFields(row, EXCEL_ROOF_NUMBER_FIELDS);
|
|
}
|
|
}
|
|
|
|
private static void coerceExcelNumberFields(Map<String, Object> map, Set<String> fields) {
|
|
if (map == null || fields == null) {
|
|
return;
|
|
}
|
|
for (String key : fields) {
|
|
if (!map.containsKey(key)) {
|
|
continue;
|
|
}
|
|
Object value = map.get(key);
|
|
Object parsed = parseExcelNumber(value);
|
|
map.put(key, parsed);
|
|
}
|
|
}
|
|
|
|
private static Object parseExcelNumber(Object value) {
|
|
if (value == null) {
|
|
return null;
|
|
}
|
|
if (value instanceof Number) {
|
|
return value;
|
|
}
|
|
if (!(value instanceof String)) {
|
|
return value;
|
|
}
|
|
String raw = ((String) value).trim();
|
|
if (raw.isEmpty()) {
|
|
return value;
|
|
}
|
|
String normalized = raw.replace(",", "");
|
|
if (!normalized.matches("[-+]?\\d+(\\.\\d+)?")) {
|
|
return value;
|
|
}
|
|
try {
|
|
return new BigDecimal(normalized);
|
|
} catch (NumberFormatException e) {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
private static void coerceExcelScale(Map<String, Object> map, String key, int scale) {
|
|
if (map == null || key == null) {
|
|
return;
|
|
}
|
|
Object value = map.get(key);
|
|
Object parsed = parseExcelNumber(value);
|
|
if (!(parsed instanceof Number)) {
|
|
return;
|
|
}
|
|
BigDecimal decimal;
|
|
if (parsed instanceof BigDecimal) {
|
|
decimal = (BigDecimal) parsed;
|
|
} else {
|
|
decimal = new BigDecimal(parsed.toString());
|
|
}
|
|
map.put(key, decimal.setScale(scale, RoundingMode.HALF_UP));
|
|
}
|
|
|
|
private static void putExcelItemList(Map<String, Object> excelData, String key,
|
|
List<ItemResponse> items) {
|
|
if (excelData == null || items == null) {
|
|
return;
|
|
}
|
|
List<Map<String, Object>> list = ExcelUtil.convertListToMap(items);
|
|
coerceExcelItemNumberFields(list);
|
|
excelData.put(key, list);
|
|
}
|
|
|
|
private static void putExcelRoofList(Map<String, Object> excelData, String key,
|
|
List<PwrGnrSimRoofResponse> items) {
|
|
if (excelData == null || items == null) {
|
|
return;
|
|
}
|
|
List<Map<String, Object>> list = ExcelUtil.convertListToMap(items);
|
|
coerceExcelRoofNumberFields(list);
|
|
excelData.put(key, list);
|
|
}
|
|
|
|
private static void applyExcelNumberFormat(Workbook workbook) {
|
|
if (workbook == null) {
|
|
return;
|
|
}
|
|
DataFormat dataFormat = workbook.createDataFormat();
|
|
short numberFormat = dataFormat.getFormat("#,##0.###");
|
|
Map<Short, CellStyle> styleCache = new HashMap<>();
|
|
|
|
for (int s = 0; s < workbook.getNumberOfSheets(); s++) {
|
|
Sheet sheet = workbook.getSheetAt(s);
|
|
if (sheet == null) {
|
|
continue;
|
|
}
|
|
for (Row row : sheet) {
|
|
for (Cell cell : row) {
|
|
CellType cellType = cell.getCellType();
|
|
CellStyle style = cell.getCellStyle();
|
|
boolean isTextFormat = style != null && "@".equals(style.getDataFormatString());
|
|
|
|
if (cellType == CellType.STRING) {
|
|
Object parsed = parseExcelNumber(cell.getStringCellValue());
|
|
if (parsed instanceof Number) {
|
|
cell.setCellValue(((Number) parsed).doubleValue());
|
|
cellType = CellType.NUMERIC;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (cellType != CellType.NUMERIC) {
|
|
continue;
|
|
}
|
|
|
|
if (!isTextFormat) {
|
|
continue;
|
|
}
|
|
|
|
short styleIdx = style.getIndex();
|
|
CellStyle cached = styleCache.get(styleIdx);
|
|
if (cached == null) {
|
|
CellStyle newStyle = workbook.createCellStyle();
|
|
newStyle.cloneStyleFrom(style);
|
|
newStyle.setDataFormat(numberFormat);
|
|
styleCache.put(styleIdx, newStyle);
|
|
cached = newStyle;
|
|
}
|
|
cell.setCellStyle(cached);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void applyExcelFixedNumberFormat(Workbook workbook, List<String> cellRefs,
|
|
String formatString) {
|
|
if (workbook == null || cellRefs == null || formatString == null) {
|
|
return;
|
|
}
|
|
DataFormat dataFormat = workbook.createDataFormat();
|
|
short numberFormat = dataFormat.getFormat(formatString);
|
|
Map<Short, CellStyle> styleCache = new HashMap<>();
|
|
|
|
for (int s = 0; s < workbook.getNumberOfSheets(); s++) {
|
|
Sheet sheet = workbook.getSheetAt(s);
|
|
if (sheet == null) {
|
|
continue;
|
|
}
|
|
for (String ref : cellRefs) {
|
|
int[] rc = parseCellRef(ref);
|
|
if (rc == null) {
|
|
continue;
|
|
}
|
|
Row row = sheet.getRow(rc[0]);
|
|
if (row == null) {
|
|
continue;
|
|
}
|
|
Cell cell = row.getCell(rc[1]);
|
|
if (cell == null) {
|
|
continue;
|
|
}
|
|
CellType cellType = cell.getCellType();
|
|
if (cellType == CellType.STRING) {
|
|
Object parsed = parseExcelNumber(cell.getStringCellValue());
|
|
if (parsed instanceof Number) {
|
|
cell.setCellValue(((Number) parsed).doubleValue());
|
|
cellType = CellType.NUMERIC;
|
|
}
|
|
}
|
|
if (cellType != CellType.NUMERIC) {
|
|
continue;
|
|
}
|
|
CellStyle style = cell.getCellStyle();
|
|
if (style == null) {
|
|
style = workbook.createCellStyle();
|
|
}
|
|
short styleIdx = style.getIndex();
|
|
CellStyle cached = styleCache.get(styleIdx);
|
|
if (cached == null) {
|
|
CellStyle newStyle = workbook.createCellStyle();
|
|
newStyle.cloneStyleFrom(style);
|
|
newStyle.setDataFormat(numberFormat);
|
|
styleCache.put(styleIdx, newStyle);
|
|
cached = newStyle;
|
|
}
|
|
cell.setCellStyle(cached);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static int[] parseCellRef(String ref) {
|
|
if (ref == null || ref.isEmpty()) {
|
|
return null;
|
|
}
|
|
int i = 0;
|
|
int col = 0;
|
|
while (i < ref.length()) {
|
|
char c = ref.charAt(i);
|
|
if (c < 'A' || c > 'Z') {
|
|
break;
|
|
}
|
|
col = col * 26 + (c - 'A' + 1);
|
|
i++;
|
|
}
|
|
if (i == 0 || i >= ref.length()) {
|
|
return null;
|
|
}
|
|
int row;
|
|
try {
|
|
row = Integer.parseInt(ref.substring(i));
|
|
} catch (NumberFormatException e) {
|
|
return null;
|
|
}
|
|
return new int[] {row - 1, col - 1};
|
|
}
|
|
|
|
/**
|
|
* QSP Q.CAST 견적서 전송 API
|
|
*
|
|
* @param estimateRequest 견적서 요청 정보
|
|
* @return String 문서번호
|
|
* @throws Exception
|
|
*/
|
|
public List<EstimateSendResponse> sendEstimateApi(EstimateRequest estimateRequest)
|
|
throws Exception {
|
|
EstimateSendRequest estimateSendRequest = new EstimateSendRequest();
|
|
List<EstimateSendResponse> quoteList = new ArrayList<EstimateSendResponse>();
|
|
String docNo = "";
|
|
|
|
try {
|
|
// 견적서 상세 조회
|
|
EstimateSendResponse estimateSendResponse =
|
|
estimateMapper.selectEstimateApiDetail(estimateRequest);
|
|
|
|
if (estimateSendResponse == null) {
|
|
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
|
|
} else {
|
|
String constructSpecification =
|
|
estimateMapper.selectEstimateConstructSpecification(estimateRequest);
|
|
|
|
estimateSendResponse.setSaveType("3");
|
|
estimateSendResponse.setSyncFlg("0");
|
|
estimateSendResponse.setConstructSpecification(
|
|
!StringUtils.isEmpty(constructSpecification) ? constructSpecification : "");
|
|
estimateSendResponse.setDelFlg("1".equals(estimateSendResponse.getDelFlg()) ? "Y" : "N");
|
|
|
|
// 아이템 목록 조회
|
|
estimateRequest.setSchBomNotExist("1");
|
|
List<ItemResponse> estimateItemList =
|
|
estimateMapper.selectEstimateItemList(estimateRequest);
|
|
estimateSendResponse.setItemList(estimateItemList);
|
|
|
|
// 첨부파일 목록 조회
|
|
FileRequest fileDeleteReq = new FileRequest();
|
|
fileDeleteReq.setObjectNo(estimateRequest.getObjectNo());
|
|
fileDeleteReq.setPlanNo(estimateRequest.getPlanNo());
|
|
fileDeleteReq.setCategory("10");
|
|
|
|
List<FileResponse> fileList = fileMapper.selectFileList(fileDeleteReq);
|
|
estimateSendResponse.setFileList(fileList);
|
|
|
|
quoteList.add(estimateSendResponse);
|
|
estimateSendRequest.setQuoteList(quoteList);
|
|
// 2차점명
|
|
estimateSendResponse.setSecSapSalesStoreCd(estimateRequest.getSecSapSalesStoreCd());
|
|
}
|
|
|
|
EstimateApiResponse response = null;
|
|
/* [1]. QSP API CALL -> Response */
|
|
String strResponse = interfaceQsp.callApi(HttpMethod.POST,
|
|
QSP_API_URL + "/api/order/qcastQuotationSave", estimateSendRequest);
|
|
|
|
if (!"".equals(strResponse)) {
|
|
com.fasterxml.jackson.databind.ObjectMapper om =
|
|
new com.fasterxml.jackson.databind.ObjectMapper()
|
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
response = om.readValue(strResponse, EstimateApiResponse.class);
|
|
|
|
@SuppressWarnings("unchecked")
|
|
Map<String, Object> result = (Map<String, Object>) response.getData();
|
|
|
|
if (result != null) {
|
|
@SuppressWarnings("unchecked")
|
|
List<Map<String, Object>> succList =
|
|
(List<Map<String, Object>>) result.get("successList");
|
|
for (Map<String, Object> succ : succList) {
|
|
if (succ != null) {
|
|
for (EstimateSendResponse data : quoteList) {
|
|
if (data.getObjectNo().equals(succ.get("objectNo"))
|
|
&& data.getPlanNo().equals(succ.get("planNo"))) {
|
|
data.setSyncFlg(String.valueOf(succ.get("syncFlg")));
|
|
data.setDocNo(String.valueOf(succ.get("docNo")));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
log.error("sendEstimateApi >>> " + message.getMessage("common.message.no.data"));
|
|
}
|
|
} catch (Exception e) {
|
|
log.error("sendEstimateApi Error >>> " + e.getMessage());
|
|
}
|
|
|
|
return quoteList;
|
|
}
|
|
|
|
/**
|
|
* 견적서 PDF HTML 생성
|
|
*
|
|
* @param doc Document
|
|
* @param data 견적서 상세정보
|
|
* @param list 견적서 아이템 목록 정보
|
|
* @return Document Document
|
|
* @throws IOException
|
|
* @throws QcastException
|
|
*/
|
|
public Document estimatePdfHtml(Document doc, EstimateResponse data, List<ItemResponse> list)
|
|
throws IOException, QcastException {
|
|
|
|
Element elm;
|
|
|
|
// 견적서 상세 정보 설정
|
|
elm = doc.getElementById("custSaleStoreName");
|
|
elm.text(StringUtils.defaultString(data.getCustSaleStoreName()));
|
|
|
|
elm = doc.getElementById("custOmit");
|
|
elm.text(StringUtils.defaultString(data.getCustOmit()));
|
|
|
|
elm = doc.getElementById("estimateValidityTerm");
|
|
elm.text(StringUtils.defaultString(data.getEstimateValidityTerm()));
|
|
|
|
elm = doc.getElementById("objectName1");
|
|
elm.text(StringUtils.defaultString(data.getObjectName()));
|
|
|
|
elm = doc.getElementById("objectNameOmit1");
|
|
elm.text(StringUtils.defaultString(data.getObjectNameOmit()));
|
|
|
|
elm = doc.getElementById("objectNo1");
|
|
elm.text(StringUtils.defaultString(data.getObjectNo()) + " / "
|
|
+ StringUtils.defaultString(data.getPlanNo()));
|
|
|
|
/*
|
|
* elm = doc.getElementById("planNo"); elm.text(StringUtils.defaultString(data.getPlanNo()));
|
|
*/
|
|
|
|
elm = doc.getElementById("estimateDate");
|
|
elm.text(StringUtils.defaultString(data.getEstimateDate()));
|
|
|
|
elm = doc.getElementById("saleStoreName");
|
|
elm.text(StringUtils.defaultString(data.getSaleStoreName()));
|
|
|
|
elm = doc.getElementById("bizNo");
|
|
elm.text(StringUtils.defaultString(data.getBizNo()));
|
|
|
|
elm = doc.getElementById("zipNo");
|
|
elm.text("(" + StringUtils.defaultString(data.getZipNo()) + ")");
|
|
|
|
elm = doc.getElementById("address");
|
|
elm.text(StringUtils.defaultString(data.getAddress()));
|
|
|
|
elm = doc.getElementById("tel");
|
|
elm.text(StringUtils.defaultString(data.getTel()));
|
|
|
|
elm = doc.getElementById("fax");
|
|
elm.text(StringUtils.defaultString(data.getFax()));
|
|
|
|
elm = doc.getElementById("totVolKw1");
|
|
elm.text(StringUtils.defaultString(data.getTotVolKw()));
|
|
|
|
elm = doc.getElementById("totPrice");
|
|
elm.text(StringUtils.defaultString(data.getTotPrice()));
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
for (ItemResponse itemResponse : list) {
|
|
sb.append("<tr>");
|
|
sb.append(
|
|
"<td style='width:60px;'>" + StringUtils.defaultString(itemResponse.getNo()) + "</td>");
|
|
sb.append("<td style='width:120px;text-align:left;'>"
|
|
+ StringUtils.defaultString(itemResponse.getItemName()) + "</td>");
|
|
sb.append("<td style='width:120px;text-align:left;'>" + StringUtils.defaultString(itemResponse.getItemNo())
|
|
+ "</td>");
|
|
sb.append(
|
|
"<td class='hide-column' style='width:80px;text-align:right;'>"
|
|
+ StringUtils.defaultString(itemResponse.getSalePrice())
|
|
+ "</td>");
|
|
sb.append("<td style='width:60px;text-align:right;'>"
|
|
+ StringUtils.defaultString(itemResponse.getAmount()) + "</td>");
|
|
sb.append(
|
|
"<td style='width:60px;'>" + StringUtils.defaultString(itemResponse.getUnit()) + "</td>");
|
|
sb.append("<td class='hide-column' style='width:80px;text-align:right;'>"
|
|
+ StringUtils.defaultString(itemResponse.getSaleTotPrice()) + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
if ("Y".equals(data.getPkgYn())) {
|
|
sb.append("<tr>");
|
|
sb.append("<td style='width:60px;'>" + StringUtils.defaultString(data.getPkgNo()) + "</td>");
|
|
sb.append("<td style='width:120px;text-align:left;'>住宅 PKG</td>");
|
|
sb.append("<td style='width:120px;text-align:left;'>-</td>");
|
|
sb.append("<td style='width:80px;text-align:right;'>"
|
|
+ StringUtils.defaultString(data.getPkgAsp()) + "</td>");
|
|
sb.append("<td style='width:60px;text-align:right;'>"
|
|
+ StringUtils.defaultString(data.getTotVol()) + "</td>");
|
|
sb.append("<td style='width:60px;'>W</td>");
|
|
sb.append("<td style='width:80px;text-align:right;'>"
|
|
+ StringUtils.defaultString(data.getPkgTotPrice()) + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
elm = doc.getElementById("itemList_detail");
|
|
elm.before(sb.toString());
|
|
|
|
elm = doc.getElementById("supplyPrice");
|
|
elm.text(StringUtils.defaultString(data.getSupplyPrice()));
|
|
|
|
elm = doc.getElementById("vatPrice");
|
|
elm.text(StringUtils.defaultString(data.getVatPrice()));
|
|
|
|
elm = doc.getElementById("totPrice1");
|
|
elm.text(StringUtils.defaultString(data.getTotPrice()));
|
|
|
|
if (!StringUtils.isEmpty(data.getRemarks())) {
|
|
elm = doc.getElementById("remarks");
|
|
elm.text(StringUtils.defaultString(data.getRemarks()));
|
|
} else {
|
|
elm = doc.getElementById("remarks");
|
|
elm.remove();
|
|
}
|
|
|
|
// 견적서 특이사항 목록 설정
|
|
// if (data.getNoteList() != null) {
|
|
// sb = new StringBuilder();
|
|
// for (NoteResponse noteResponse : data.getNoteList()) {
|
|
// sb.append("<tr>");
|
|
// sb.append("<td style='text-align:left;'>"
|
|
// + StringUtils.defaultString(noteResponse.getCodeNm()) + "</td>");
|
|
// sb.append("<td style='text-align:left;'>" + StringUtils
|
|
// .defaultString(noteResponse.getRemarks()).replaceAll("\r\n|\r|\n", "<br />") + "</td>");
|
|
// sb.append("</tr>");
|
|
// }
|
|
// elm = doc.getElementById("noteList_detail");
|
|
// elm.append(sb.toString());
|
|
// }
|
|
|
|
// 도면 설정
|
|
elm = doc.getElementById("objectNo4");
|
|
elm.text(StringUtils.defaultString(data.getObjectNo()) + " (Plan No : "
|
|
+ StringUtils.defaultString(data.getPlanNo()) + ")");
|
|
|
|
elm = doc.getElementById("objectName");
|
|
elm.text(StringUtils.defaultString(data.getObjectName()) + " " + StringUtils.defaultString(data.getObjectNameOmit()));
|
|
|
|
elm = doc.getElementById("totVolKw");
|
|
elm.text(StringUtils.defaultString(data.getTotVolKw()) + " Kw");
|
|
|
|
elm = doc.getElementById("certVolKw");
|
|
elm.text(StringUtils.defaultString(data.getRoofInfo().getCertVolKw()) + " Kw");
|
|
|
|
elm = doc.getElementById("drawingEstimateCreateDate4");
|
|
elm.text(StringUtils.defaultString(data.getDrawingEstimateCreateDate()));
|
|
|
|
elm = doc.getElementById("prefName4");
|
|
elm.text(StringUtils.defaultString(data.getPrefName()));
|
|
|
|
elm = doc.getElementById("areaName4");
|
|
elm.text(StringUtils.defaultString(data.getAreaName()));
|
|
|
|
elm = doc.getElementById("snowfall4");
|
|
elm.text(StringUtils.defaultString(data.getSnowfall()) + " cm");
|
|
|
|
elm = doc.getElementById("standardWindSpeedName4");
|
|
elm.text(StringUtils.defaultString(data.getStandardWindSpeedName()));
|
|
|
|
// elm = doc.getElementById("deg1");
|
|
// elm.text(StringUtils.defaultString(data.getRoofInfo().getCompasDeg())+"°");
|
|
|
|
// 도면(가대제외 이미지)
|
|
if (data.getDrawingImg1() != null) {
|
|
elm = doc.getElementById("drawingImg1");
|
|
String imgSrc1 = Base64.getEncoder().encodeToString(data.getDrawingImg1());
|
|
elm.html("<img src='data:image/png;base64," + imgSrc1 + "' width='100%'/>");
|
|
}
|
|
|
|
if (data.getRoofInfo().getCompasDegImg() != null) {
|
|
elm = doc.getElementById("degImg1");
|
|
String imgSrc1 = Base64.getEncoder().encodeToString(data.getRoofInfo().getCompasDegImg());
|
|
elm.html(
|
|
"<img src='data:image/png;base64,"
|
|
+ imgSrc1
|
|
+ "' width='50'/><div class=\"guide-img-tit\" >"+ StringUtils.defaultString(data.getRoofInfo().getCompasDeg()) + "°</div>");
|
|
}
|
|
|
|
|
|
int no = 1;
|
|
sb = new StringBuilder();
|
|
for (ItemResponse itemResponse : list) {
|
|
if (!"STAND_".equals(itemResponse.getItemGroup())) {
|
|
sb.append("<tr>");
|
|
sb.append("<td>" + (no++) + "</td>");
|
|
sb.append("<td style='text-align:left;'>"
|
|
+ StringUtils.defaultString(itemResponse.getItemNo()) + "</td>");
|
|
sb.append("<td style='text-align:right;'>"
|
|
+ StringUtils.defaultString(itemResponse.getAmount()) + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
}
|
|
elm = doc.getElementById("notStandItemList_detail");
|
|
elm.append(sb.toString());
|
|
|
|
if (data.getRoofInfo().getCircuitItemList() != null) {
|
|
no = 1;
|
|
sb = new StringBuilder();
|
|
for (ItemResponse itemResponse : data.getRoofInfo().getCircuitItemList()) {
|
|
sb.append("<tr>");
|
|
sb.append("<td>" + (no++) + "</td>");
|
|
sb.append(
|
|
"<td style='text-align:left;'>" + StringUtils.defaultString(itemResponse.getItemNo())
|
|
+ " [" + itemResponse.getCircuitCfg() + "]" + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
elm = doc.getElementById("pcsItemList_detail");
|
|
elm.append(sb.toString());
|
|
}
|
|
|
|
if (data.getRoofInfo().getRoofVolList() != null) {
|
|
sb = new StringBuilder();
|
|
for (RoofResponse roofResponse : data.getRoofInfo().getRoofVolList()) {
|
|
sb.append("<tr>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getRoofSurface()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getClassTypeName()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getAmount()) + "</td>");
|
|
sb.append("<td style='text-align:right;'>"
|
|
+ StringUtils.defaultString(roofResponse.getVolKw()) + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
elm = doc.getElementById("surFaceList_detail");
|
|
elm.before(sb.toString());
|
|
|
|
elm = doc.getElementById("moduleTotAmount");
|
|
elm.text(StringUtils.defaultString(data.getRoofInfo().getModuleTotAmount()));
|
|
|
|
elm = doc.getElementById("moduleTotVolKw");
|
|
elm.text(StringUtils.defaultString(data.getRoofInfo().getModuleTotVolKw()));
|
|
}
|
|
|
|
if (data.getRoofInfo().getRoofList() != null) {
|
|
sb = new StringBuilder();
|
|
for (RoofResponse roofResponse : data.getRoofInfo().getRoofList()) {
|
|
sb.append("<tr>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getRoofSurface()) + "</td>");
|
|
sb.append("<td style='text-align:left;'>"
|
|
+ StringUtils.defaultString(roofResponse.getRoofMaterialName()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getClassTypeName()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getConstructSpecificationName())
|
|
+ "</td>");
|
|
sb.append("<td style='text-align:left;'>"
|
|
+ StringUtils.defaultString(roofResponse.getSupportMethodName()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getSurfaceType()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getSetupHeight()) + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
elm = doc.getElementById("surFaceList_detail2");
|
|
elm.before(sb.toString());
|
|
}
|
|
|
|
elm = doc.getElementById("objectNo5");
|
|
elm.text(StringUtils.defaultString(data.getObjectNo()) + " (Plan No : "
|
|
+ StringUtils.defaultString(data.getPlanNo()) + ")");
|
|
|
|
elm = doc.getElementById("objectName5");
|
|
elm.text(StringUtils.defaultString(data.getObjectName()) + " " + StringUtils.defaultString(data.getObjectNameOmit()));
|
|
|
|
elm = doc.getElementById("totVolKw5");
|
|
elm.text(StringUtils.defaultString(data.getTotVolKw()) + " Kw");
|
|
|
|
elm = doc.getElementById("certVolKw5");
|
|
elm.text(StringUtils.defaultString(data.getRoofInfo().getCertVolKw()) + " Kw");
|
|
|
|
elm = doc.getElementById("drawingEstimateCreateDate5");
|
|
elm.text(StringUtils.defaultString(data.getDrawingEstimateCreateDate()));
|
|
|
|
elm = doc.getElementById("prefName5");
|
|
elm.text(StringUtils.defaultString(data.getPrefName()));
|
|
|
|
elm = doc.getElementById("areaName5");
|
|
elm.text(StringUtils.defaultString(data.getAreaName()));
|
|
|
|
elm = doc.getElementById("snowfall5");
|
|
elm.text(StringUtils.defaultString(data.getSnowfall()) + " cm");
|
|
|
|
elm = doc.getElementById("standardWindSpeedName5");
|
|
elm.text(StringUtils.defaultString(data.getStandardWindSpeedName()));
|
|
|
|
// 도면(가대 이미지)
|
|
if (data.getDrawingImg2() != null) {
|
|
elm = doc.getElementById("drawingImg2");
|
|
String imgSrc2 = Base64.getEncoder().encodeToString(data.getDrawingImg2());
|
|
elm.html("<img src='data:image/png;base64," + imgSrc2 + "' width='100%'/>");
|
|
}
|
|
|
|
if (data.getRoofInfo().getCompasDegImg() != null) {
|
|
elm = doc.getElementById("degImg2");
|
|
String imgSrc2 = Base64.getEncoder().encodeToString(data.getRoofInfo().getCompasDegImg());
|
|
elm.html(
|
|
"<img src='data:image/png;base64,"
|
|
+ imgSrc2
|
|
+ "' width='50'/><div class=\"guide-img-tit\" >"+ StringUtils.defaultString(data.getRoofInfo().getCompasDeg()) + "°</div>");
|
|
}
|
|
|
|
no = 1;
|
|
sb = new StringBuilder();
|
|
for (ItemResponse itemResponse : list) {
|
|
if ("STAND_".equals(itemResponse.getItemGroup())) {
|
|
sb.append("<tr>");
|
|
sb.append("<td>" + (no++) + "</td>");
|
|
sb.append("<td style='text-align:left;'>"
|
|
+ StringUtils.defaultString(itemResponse.getItemNo()) + "</td>");
|
|
sb.append("<td style='text-align:right;'>"
|
|
+ StringUtils.defaultString(itemResponse.getAmount()) + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
}
|
|
elm = doc.getElementById("standItemList_detail");
|
|
elm.append(sb.toString());
|
|
|
|
if (data.getRoofInfo().getRoofList() != null) {
|
|
sb = new StringBuilder();
|
|
for (RoofResponse roofResponse : data.getRoofInfo().getRoofList()) {
|
|
sb.append("<tr>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getRoofSurface()) + "</td>");
|
|
sb.append("<td style='text-align:left;'>"
|
|
+ StringUtils.defaultString(roofResponse.getRoofMaterialName()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getClassTypeName()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getConstructSpecificationName())
|
|
+ "</td>");
|
|
sb.append("<td style='text-align:left;'>"
|
|
+ StringUtils.defaultString(roofResponse.getSupportMethodName()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getSurfaceType()) + "</td>");
|
|
sb.append("<td>" + StringUtils.defaultString(roofResponse.getSetupHeight()) + "</td>");
|
|
sb.append("</tr>");
|
|
}
|
|
elm = doc.getElementById("roofList_detail");
|
|
elm.before(sb.toString());
|
|
}
|
|
|
|
elm = doc.getElementById("objectNo6");
|
|
elm.text(StringUtils.defaultString(data.getObjectNo()) + " (Plan No : "
|
|
+ StringUtils.defaultString(data.getPlanNo()) + ")");
|
|
|
|
elm = doc.getElementById("objectName6");
|
|
elm.text(StringUtils.defaultString(data.getObjectName()));
|
|
|
|
elm = doc.getElementById("objectNameOmit6");
|
|
elm.text(StringUtils.defaultString(data.getObjectNameOmit()));
|
|
|
|
sb = new StringBuilder();
|
|
BigDecimal totGrossWt = BigDecimal.ZERO;
|
|
|
|
for (ItemResponse itemResponse : list) {
|
|
|
|
String amountStr = StringUtils.defaultString(itemResponse.getAmount());
|
|
String grossWtStr = StringUtils.defaultString(itemResponse.getGrossWt());
|
|
|
|
// 빈 문자열 체크
|
|
if (amountStr.isEmpty() || grossWtStr.isEmpty()) {
|
|
sb.append("<tr><td colspan=5></td></tr>");
|
|
} else {
|
|
BigDecimal amount = new BigDecimal(amountStr);
|
|
BigDecimal grossWt = new BigDecimal(grossWtStr);
|
|
// grossWt가 0보다 큰지 체크
|
|
if (grossWt.compareTo(BigDecimal.ZERO) > 0) {
|
|
BigDecimal totalWeight = amount.multiply(grossWt);
|
|
totGrossWt = totGrossWt.add(totalWeight);
|
|
elm = doc.getElementById("totGrossWt");
|
|
elm.text(totGrossWt.toString());
|
|
|
|
sb.append("<tr>");
|
|
sb.append("<td style='width:120px;text-align:left;'>")
|
|
.append(StringUtils.defaultString(itemResponse.getItemName()))
|
|
.append("</td>");
|
|
sb.append("<td style='width:120px;text-align:left;'>")
|
|
.append(StringUtils.defaultString(itemResponse.getItemNo()))
|
|
.append("</td>");
|
|
sb.append("<td style='width:60px;text-align:right;'>").append(amountStr).append("</td>");
|
|
sb.append("<td style='width:60px;text-align:right;'>").append(totalWeight.toString()).append("</td>");
|
|
sb.append("<td style='width:60px;text-align:right;'>").append(grossWtStr).append("</td>");
|
|
sb.append("</tr>");
|
|
|
|
}
|
|
}
|
|
}
|
|
elm = doc.getElementById("weightList_detail");
|
|
elm.before(sb.toString());
|
|
|
|
return doc;
|
|
}
|
|
|
|
/**
|
|
* Plan 확정 정보 동기화
|
|
*
|
|
* @param planSyncList Plan 목록
|
|
* @return
|
|
* @throws Exception
|
|
*/
|
|
public int setPlanConfirmSyncSave(List<PlanSyncResponse> planSyncList) throws Exception {
|
|
int cnt = 0;
|
|
for (PlanSyncResponse planSyncData : planSyncList) {
|
|
// Plan 확정 처리
|
|
cnt += estimateMapper.updatePlanConfirmSync(planSyncData);
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* QSP Q.CAST 견적서 동기화 실패 목록
|
|
*
|
|
* @return EstimateSendRequest 견적서 실패 목록
|
|
* @throws Exception
|
|
*/
|
|
public EstimateSendRequest selectEstimateSyncFailList() throws Exception {
|
|
EstimateSendRequest estimateSendRequest = new EstimateSendRequest();
|
|
List<EstimateSendResponse> quoteList = new ArrayList<EstimateSendResponse>();
|
|
String docNo = "";
|
|
|
|
// 견적서 동기화 실패 목록 조회
|
|
List<EstimateSendResponse> estimateSendListResponse =
|
|
estimateMapper.selectEstimateApiFailList();
|
|
|
|
for (EstimateSendResponse estimateSendResponse : estimateSendListResponse) {
|
|
EstimateRequest estimateRequest = new EstimateRequest();
|
|
estimateRequest.setObjectNo(estimateSendResponse.getObjectNo());
|
|
estimateRequest.setPlanNo(estimateSendResponse.getPlanNo());
|
|
|
|
String constructSpecification =
|
|
estimateMapper.selectEstimateConstructSpecification(estimateRequest);
|
|
|
|
estimateSendResponse.setSaveType("3");
|
|
estimateSendResponse.setSyncFlg("0");
|
|
estimateSendResponse.setConstructSpecification(
|
|
!StringUtils.isEmpty(constructSpecification) ? constructSpecification : "");
|
|
estimateSendResponse.setDelFlg("1".equals(estimateSendResponse.getDelFlg()) ? "Y" : "N");
|
|
|
|
// 아이템 목록 조회
|
|
estimateRequest.setSchBomNotExist("1");
|
|
List<ItemResponse> estimateItemList = estimateMapper.selectEstimateItemList(estimateRequest);
|
|
estimateSendResponse.setItemList(estimateItemList);
|
|
|
|
// 첨부파일 목록 조회
|
|
FileRequest fileDeleteReq = new FileRequest();
|
|
fileDeleteReq.setObjectNo(estimateRequest.getObjectNo());
|
|
fileDeleteReq.setPlanNo(estimateRequest.getPlanNo());
|
|
fileDeleteReq.setCategory("10");
|
|
|
|
List<FileResponse> fileList = fileMapper.selectFileList(fileDeleteReq);
|
|
estimateSendResponse.setFileList(fileList);
|
|
|
|
quoteList.add(estimateSendResponse);
|
|
estimateSendRequest.setQuoteList(quoteList);
|
|
}
|
|
|
|
return estimateSendRequest;
|
|
}
|
|
|
|
/**
|
|
* 견적서 정보 QSP 동기화
|
|
*
|
|
* @param planSyncList Plan 목록
|
|
* @return
|
|
* @throws Exception
|
|
*/
|
|
public int setEstimateSyncSave(List<PlanSyncResponse> planSyncList) throws Exception {
|
|
int cnt = 0;
|
|
for (PlanSyncResponse planSyncData : planSyncList) {
|
|
EstimateRequest estimateRequest = new EstimateRequest();
|
|
estimateRequest.setObjectNo(planSyncData.getObjectNo());
|
|
estimateRequest.setPlanNo(planSyncData.getPlanNo());
|
|
estimateRequest.setDocNo(planSyncData.getDocNo());
|
|
estimateRequest.setSyncFlg(planSyncData.getSyncFlg());
|
|
estimateRequest.setUserId("system");
|
|
|
|
// 견적서 동기화 여부 처리
|
|
cnt += estimateMapper.updateEstimateApi(estimateRequest);
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* PC 회로 구성도 설정
|
|
*
|
|
* @param pcsItemList
|
|
* @param moduleList
|
|
* @return
|
|
*/
|
|
private List<ItemRequest> getPcsCircuitList(List<ItemRequest> pcsItemList,
|
|
List<ItemRequest> moduleList) {
|
|
|
|
if (pcsItemList != null && pcsItemList.size() > 0) {
|
|
|
|
for (ItemRequest itemRequest : moduleList) {
|
|
itemRequest
|
|
.setCircuit(itemRequest.getCircuit().replaceAll("\\(", "").replaceAll("\\)", ""));
|
|
}
|
|
|
|
if (pcsItemList.size() == 1) {
|
|
pcsItemList.get(0).setCircuitCfg(this.getPcsCircuitCtg(moduleList));
|
|
} else {
|
|
if (moduleList != null && moduleList.size() > 0) {
|
|
int j = 1;
|
|
for (ItemRequest data : pcsItemList) {
|
|
String val = String.valueOf(j);
|
|
|
|
List<ItemRequest> resultList = moduleList.stream()
|
|
.filter(t -> StringUtils.equals(val, t.getCircuit().split("-")[0]))
|
|
.collect(Collectors.toList());
|
|
data.setCircuitCfg(this.getPcsCircuitCtg(resultList));
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pcsItemList;
|
|
}
|
|
|
|
/**
|
|
* PC 회로구성도 조회
|
|
*
|
|
* @param circuitList
|
|
* @return
|
|
*/
|
|
private String getPcsCircuitCtg(List<ItemRequest> circuitList) {
|
|
|
|
String circuitCfg = "";
|
|
|
|
if (circuitList != null && circuitList.size() > 0) {
|
|
// ArrayList 생성 변환
|
|
ArrayList<String> list = new ArrayList<String>();
|
|
for (ItemRequest pcsSerItemReq : circuitList) {
|
|
list.add(pcsSerItemReq.getCircuit());
|
|
}
|
|
|
|
// ArrayList 회로 중복수 오름차순 정렬
|
|
Set<String> set = new HashSet<String>(list);
|
|
List<String> setList = new ArrayList<>(set);
|
|
|
|
Collections.sort(setList, new Comparator<String>() {
|
|
@Override
|
|
public int compare(String o1, String o2) {
|
|
int first = Integer.parseInt(o1.split("-")[0]);
|
|
int second = Integer.parseInt(o2.split("-")[0]);
|
|
return second > first ? -1 : second < first ? 1 : 0; // 오름차순 정렬
|
|
}
|
|
});
|
|
|
|
for (String str : setList) {
|
|
if (!StringUtils.isEmpty(circuitCfg))
|
|
circuitCfg += ", ";
|
|
circuitCfg += Collections.frequency(list, str);
|
|
}
|
|
}
|
|
|
|
return circuitCfg;
|
|
}
|
|
|
|
public EstimateApiResponse selectAgencyCustList(PriceRequest priceRequest) throws Exception {
|
|
// Validation
|
|
|
|
if (StringUtils.isEmpty(priceRequest.getSapSalesStoreCd())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Sap Sale Store Code"));
|
|
}
|
|
|
|
|
|
EstimateApiResponse response = null;
|
|
/* [1]. QSP API (url + param) Setting */
|
|
String url = QSP_API_URL + "/api/master/agencyCustList";
|
|
String apiUrl = UriComponentsBuilder.fromHttpUrl(url)
|
|
.queryParam("sapSalesStoreCd", priceRequest.getSapSalesStoreCd()).build().toUriString();
|
|
|
|
/* [2]. QSP API CALL -> Response */
|
|
String strResponse = interfaceQsp.callApi(HttpMethod.GET, apiUrl, null);
|
|
|
|
if (!"".equals(strResponse)) {
|
|
com.fasterxml.jackson.databind.ObjectMapper om =
|
|
new com.fasterxml.jackson.databind.ObjectMapper()
|
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
response = om.readValue(strResponse, EstimateApiResponse.class);
|
|
} else {
|
|
// [msg] No data
|
|
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* 견적서 삭제 (복사이후 배치면 저장)
|
|
* @param estimateRequest
|
|
* @throws Exception
|
|
*/
|
|
|
|
public void deleteEstimate(EstimateRequest estimateRequest) throws Exception{
|
|
|
|
if (StringUtils.isEmpty(estimateRequest.getObjectNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getPlanNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getUserId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "User ID"));
|
|
}
|
|
|
|
try {
|
|
// T_PLAN
|
|
int cnt = estimateMapper.updateEstimateInit(estimateRequest);
|
|
// T_PLAN_INFO
|
|
int cnt2 = estimateMapper.updateEstimateInfoInit(estimateRequest);
|
|
|
|
// 견적서 모든 아이템 제거
|
|
int cnt3 = estimateMapper.deleteEstimateItemList(estimateRequest);
|
|
int cnt4 = estimateMapper.deleteEstimateInfoItemList(estimateRequest);
|
|
|
|
} catch (Exception e) {
|
|
log.error("Failed to delete estimate. Request: {}", estimateRequest, e);
|
|
throw e; // 예외를 재던지기하여 상위 계층에서도 예외를 처리할 수 있도록 함
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* 워크북에서 시트를 안전하게 제거하는 헬퍼 메소드
|
|
* 시트가 존재하지 않으면 무시함
|
|
*
|
|
* @param workbook 워크북
|
|
* @param sheetName 제거할 시트명
|
|
*/
|
|
private void safeRemoveSheet(Workbook workbook, String sheetName) {
|
|
int sheetIndex = workbook.getSheetIndex(sheetName);
|
|
if (sheetIndex >= 0) {
|
|
workbook.removeSheetAt(sheetIndex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 엑셀 워크북의 모든 시트에서 이미지의 가로세로 비율을 보정
|
|
* JXLS jx:image 가 셀 영역에 맞춰 이미지를 늘리기 때문에 원본 비율로 재조정
|
|
*/
|
|
private void adjustImageAspectRatio(Workbook workbook) {
|
|
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
|
|
Sheet sheet = workbook.getSheetAt(i);
|
|
if (!(sheet instanceof XSSFSheet)) continue;
|
|
|
|
XSSFDrawing drawing = ((XSSFSheet) sheet).getDrawingPatriarch();
|
|
if (drawing == null) continue;
|
|
|
|
for (XSSFShape shape : drawing.getShapes()) {
|
|
if (!(shape instanceof XSSFPicture)) continue;
|
|
|
|
XSSFPicture picture = (XSSFPicture) shape;
|
|
XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor();
|
|
PictureData pictureData = picture.getPictureData();
|
|
if (pictureData == null) continue;
|
|
|
|
// 원본 이미지 크기 (EMU 단위)
|
|
java.awt.Dimension imgDim = picture.getImageDimension();
|
|
if (imgDim == null || imgDim.width == 0 || imgDim.height == 0) continue;
|
|
|
|
double imgRatio = (double) imgDim.width / imgDim.height;
|
|
|
|
// 현재 앵커 영역의 실제 크기 계산 (EMU 단위)
|
|
long cellWidthEmu = 0;
|
|
for (int col = anchor.getCol1(); col < anchor.getCol2(); col++) {
|
|
int colWidth = sheet.getColumnWidth(col); // 1/256 of character width
|
|
cellWidthEmu += (long) (colWidth / 256.0 * Units.DEFAULT_CHARACTER_WIDTH * Units.EMU_PER_PIXEL);
|
|
}
|
|
// dx 오프셋 보정
|
|
cellWidthEmu = cellWidthEmu - anchor.getDx1() + anchor.getDx2();
|
|
|
|
long cellHeightEmu = 0;
|
|
for (int row = anchor.getRow1(); row < anchor.getRow2(); row++) {
|
|
Row r = sheet.getRow(row);
|
|
float heightPt = (r != null) ? r.getHeightInPoints() : sheet.getDefaultRowHeightInPoints();
|
|
cellHeightEmu += Units.toEMU(heightPt);
|
|
}
|
|
// dy 오프셋 보정
|
|
cellHeightEmu = cellHeightEmu - anchor.getDy1() + anchor.getDy2();
|
|
|
|
if (cellWidthEmu <= 0 || cellHeightEmu <= 0) continue;
|
|
|
|
double cellRatio = (double) cellWidthEmu / cellHeightEmu;
|
|
|
|
if (imgRatio > cellRatio) {
|
|
// 이미지가 더 넓음 → 너비에 맞추고 높이를 줄임
|
|
long newHeightEmu = (long) (cellWidthEmu / imgRatio);
|
|
long verticalPadding = (cellHeightEmu - newHeightEmu) / 2;
|
|
|
|
// dy1 오프셋으로 세로 중앙 정렬
|
|
anchor.setDy1((int) (anchor.getDy1() + verticalPadding));
|
|
// row2/dy2 재계산
|
|
long remainHeight = newHeightEmu;
|
|
int newRow2 = anchor.getRow1();
|
|
// dy1 오프셋이 있는 첫 행 처리
|
|
Row firstRow = sheet.getRow(newRow2);
|
|
float firstRowPt = (firstRow != null) ? firstRow.getHeightInPoints() : sheet.getDefaultRowHeightInPoints();
|
|
long firstRowAvail = Units.toEMU(firstRowPt) - anchor.getDy1();
|
|
if (remainHeight <= firstRowAvail) {
|
|
anchor.setRow2(newRow2);
|
|
anchor.setDy2((int) (anchor.getDy1() + remainHeight));
|
|
} else {
|
|
remainHeight -= firstRowAvail;
|
|
newRow2++;
|
|
while (remainHeight > 0) {
|
|
Row r = sheet.getRow(newRow2);
|
|
float hPt = (r != null) ? r.getHeightInPoints() : sheet.getDefaultRowHeightInPoints();
|
|
long rowEmu = Units.toEMU(hPt);
|
|
if (remainHeight <= rowEmu) {
|
|
anchor.setRow2(newRow2);
|
|
anchor.setDy2((int) remainHeight);
|
|
remainHeight = 0;
|
|
} else {
|
|
remainHeight -= rowEmu;
|
|
newRow2++;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// 이미지가 더 높음 → 높이에 맞추고 너비를 줄임
|
|
long newWidthEmu = (long) (cellHeightEmu * imgRatio);
|
|
long horizontalPadding = (cellWidthEmu - newWidthEmu) / 2;
|
|
|
|
// dx1 오프셋으로 가로 중앙 정렬
|
|
anchor.setDx1((int) (anchor.getDx1() + horizontalPadding));
|
|
// col2/dx2 재계산
|
|
long remainWidth = newWidthEmu;
|
|
int newCol2 = anchor.getCol1();
|
|
// dx1 오프셋이 있는 첫 열 처리
|
|
int firstColW = sheet.getColumnWidth(newCol2);
|
|
long firstColEmu = (long) (firstColW / 256.0 * Units.DEFAULT_CHARACTER_WIDTH * Units.EMU_PER_PIXEL);
|
|
long firstColAvail = firstColEmu - anchor.getDx1();
|
|
if (remainWidth <= firstColAvail) {
|
|
anchor.setCol2(newCol2);
|
|
anchor.setDx2((int) (anchor.getDx1() + remainWidth));
|
|
} else {
|
|
remainWidth -= firstColAvail;
|
|
newCol2++;
|
|
while (remainWidth > 0) {
|
|
int colW = sheet.getColumnWidth(newCol2);
|
|
long colEmu = (long) (colW / 256.0 * Units.DEFAULT_CHARACTER_WIDTH * Units.EMU_PER_PIXEL);
|
|
if (remainWidth <= colEmu) {
|
|
anchor.setCol2(newCol2);
|
|
anchor.setDx2((int) remainWidth);
|
|
remainWidth = 0;
|
|
} else {
|
|
remainWidth -= colEmu;
|
|
newCol2++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Autowired
|
|
private org.springframework.core.env.Environment environment;
|
|
|
|
private byte[] loadDrawingImage(URL url) {
|
|
try {
|
|
URLConnection connection = url.openConnection();
|
|
// local 프로파일일 때만 SSL 우회
|
|
if (environment.matchesProfiles("local") && connection instanceof javax.net.ssl.HttpsURLConnection httpsConn) {
|
|
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("TLSv1.2");
|
|
sc.init(null, new javax.net.ssl.TrustManager[]{new javax.net.ssl.X509TrustManager() {
|
|
public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
|
|
public void checkClientTrusted(java.security.cert.X509Certificate[] c, String t) {}
|
|
public void checkServerTrusted(java.security.cert.X509Certificate[] c, String t) {}
|
|
}}, null);
|
|
httpsConn.setSSLSocketFactory(sc.getSocketFactory());
|
|
httpsConn.setHostnameVerifier((h, s) -> true);
|
|
}
|
|
if (connection instanceof HttpURLConnection) {
|
|
if (((HttpURLConnection) connection).getResponseCode() != HttpURLConnection.HTTP_OK) {
|
|
return null;
|
|
}
|
|
}
|
|
try (InputStream imageInputStream = connection.getInputStream()) {
|
|
return imageInputStream.readAllBytes();
|
|
}
|
|
} catch (Exception e) {
|
|
log.warn("Failed to load drawing image. url={}", url, e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 발전시뮬레이션 견적서 목록 조회
|
|
*
|
|
* @param objectRequest 견적서 정보(물건번호, 플랜번호)
|
|
* @return EstimateResponse 견적서 상세 정보
|
|
* @throws Exception
|
|
*/
|
|
public SimulationEstimateListResponse selectSimulationEstimateList(ObjectRequest objectRequest) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(objectRequest.getSaleStoreId())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Sales Store ID"));
|
|
}
|
|
|
|
SimulationEstimateListResponse response = new SimulationEstimateListResponse();
|
|
|
|
if (!"T01".equals(objectRequest.getSaleStoreId())) {
|
|
objectRequest.setSchSelSaleStoreId("");
|
|
}
|
|
|
|
// 견적서 목록 조회
|
|
List<ObjectResponse> objectList = estimateMapper.selectSimulationEstimateList(objectRequest);
|
|
|
|
if (objectList == null) {
|
|
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
|
|
} else {
|
|
response.setObjectList(objectList);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* 발전시뮬레이션 견적서 상세 조회
|
|
*
|
|
* @param estimateRequest 견적서 정보(물건번호, 플랜번호)
|
|
* @return EstimateResponse 견적서 상세 정보
|
|
* @throws Exception
|
|
*/
|
|
public SimulationEstimateResponse selectSimulationEstimateInfo(EstimateRequest estimateRequest) throws Exception {
|
|
// Validation
|
|
if (StringUtils.isEmpty(estimateRequest.getObjectNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
if (StringUtils.isEmpty(estimateRequest.getPlanNo())) {
|
|
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Plan No"));
|
|
}
|
|
|
|
SimulationEstimateResponse response = new SimulationEstimateResponse();
|
|
|
|
// 견적서 상세 조회
|
|
EstimateResponse estimateResponse = estimateMapper.selectEstimateDetail(estimateRequest);
|
|
|
|
if (estimateResponse == null) {
|
|
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
|
|
} else {
|
|
|
|
// 지역코드 셋팅
|
|
response.setObjectNo(estimateRequest.getObjectNo());
|
|
response.setPlanNo(estimateRequest.getPlanNo());
|
|
response.setAreaId(estimateResponse.getAreaId());
|
|
|
|
// 지붕면 정보 목록 조회
|
|
List<SimulationRoofResponse> roofList = estimateMapper.selectSimulationEstimateRoofList(estimateRequest);
|
|
// 지붕면 설치 모듈 정보 목록 조회
|
|
List<SimulationItemResponse> roofModuleList = estimateMapper.selectSimulationEstimateRoofModuleList(estimateRequest);
|
|
|
|
// roofModuleList roofSurfaceId 기준으로 그룹핑
|
|
Map<String, List<SimulationItemResponse>> roofItemMap = roofModuleList.stream()
|
|
.collect(Collectors.groupingBy(SimulationItemResponse::getRoofSurfaceId));
|
|
|
|
// roofList 각 항목에 매핑된 roofModuleList 세팅
|
|
roofList.forEach(roof ->
|
|
roof.setRoofModuleList(
|
|
roofItemMap.getOrDefault(roof.getRoofSurfaceId(), Collections.emptyList())
|
|
)
|
|
);
|
|
|
|
// 지붕면 설치 PCS 목록 조회
|
|
List<SimulationItemResponse> pcsList = estimateMapper.selectSimulationEstimateRoofPcsList(estimateRequest);
|
|
|
|
response.setRoofList(roofList);
|
|
response.setPcsList(pcsList);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
}
|