570 lines
23 KiB
Java

package com.interplug.qcast.biz.estimate;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.interplug.qcast.biz.estimate.dto.*;
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.ObjectResponse;
import com.interplug.qcast.biz.object.dto.PlanRequest;
import com.interplug.qcast.biz.object.dto.PlanResponse;
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.InterfaceQsp;
import io.micrometer.common.util.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.UriComponentsBuilder;
@Slf4j
@Service
@RequiredArgsConstructor
public class EstimateService {
private final InterfaceQsp interfaceQsp;
@Autowired Messages message;
@Value("${qsp.url}")
private String QSP_API_URL;
private final ObjectMapper objectMapper;
private final EstimateMapper estimateMapper;
private final FileMapper fileMapper;
public PriceResponse 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.getDocTpCd())) {
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Estimate Type"));
}
PriceResponse 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("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, PriceResponse.class);
} else {
// [msg] No data
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
}
return response;
}
public PriceResponse 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"));
}
PriceResponse 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, PriceResponse.class);
} else {
// [msg] No data
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
}
return response;
}
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"));
}
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 {
// 아이템 목록 조회
List<ItemResponse> estimateItemList = estimateMapper.selectEstimateItemList(estimateRequest);
response.setItemList(estimateItemList);
// 총 합산금액 계산
this.selectTotalPriceInfo(response);
// 첨부파일 목록 조회
FileRequest fileDeleteReq = new FileRequest();
fileDeleteReq.setObjectNo(objectNo);
fileDeleteReq.setCategory("10");
fileDeleteReq.setPlanNo(planNo);
List<FileResponse> fileList = fileMapper.selectFileList(fileDeleteReq);
response.setFileList(fileList);
}
return response;
}
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.getSapSalesStoreCd())) {
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Sap Sale Store Code"));
}
String splitStr = "";
List<ItemRequest> itemList = estimateRequest.getItemList();
// 도면 작성일 경우에만 지붕재 데이터를 셋팅
if ("1".equals(estimateRequest.getDrawingFlg())) {
// [1]. 견적서 기본셋팅
estimateRequest.setEstimateType("YJOD");
estimateRequest.setPriceCd("UNIT_PRICE");
// 물건정보 조회 후 데이터 축출
ObjectResponse objectResponse =
objectMapper.selectObjectDetail(estimateRequest.getObjectNo());
if (objectResponse != null) {
estimateRequest.setWeatherPoint(
objectResponse.getPrefName() + " - " + objectResponse.getAreaName());
estimateRequest.setCharger(objectResponse.getReceiveUser());
}
// [2]. 지붕재 관련 데이터 셋팅
List<RoofRequest> roofList = estimateRequest.getRoofList();
// 지붕재 아이템 ID
String roofMaterialIds = "";
// 지붕재 공법 ID
String supportMethodIds = "";
// 지붕재 시공사양 ID
String constructSpecifications = "";
// 지붕재 아이템명
String roofMaterialIdMultis = "";
// 지붕재 공법명
String supportMethodIdMultis = "";
// 가대 메이커명
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.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.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);
int j = 1;
for (ItemRequest itemRequest : itemList) {
itemRequest.setDispOrder(String.valueOf(j++));
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.setItemGroup(itemResponse.getItemGroup());
break;
}
}
}
// [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.getSaltAreaFlg())) {
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
estimateOptions += "ATTR005"; // 염해지역 체크
} else if ("ATTR006".equals(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) {
estimateOptions += !StringUtils.isEmpty(estimateOptions) ? splitStr : "";
estimateOptions += noteResponse.getCode();
}
estimateRequest.setEstimateOption(estimateOptions);
}
// 아아템 목록 필수 값 체크
BigDecimal capacity = BigDecimal.ZERO;
String moduleModel = "";
String pcTypeNo = "";
for (ItemRequest itemRequest : itemList) {
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);
// 물건정보 수정
if (!StringUtils.isEmpty(estimateRequest.getObjectName())
|| !StringUtils.isEmpty(estimateRequest.getSurfaceType())
|| !StringUtils.isEmpty(estimateRequest.getSetupHeight())
|| !StringUtils.isEmpty(estimateRequest.getStandardWindSpeedId())
|| !StringUtils.isEmpty(estimateRequest.getSnowfall())) {
estimateMapper.updateObject(estimateRequest);
}
// 견적서 정보 수정
estimateRequest.setPriceCd("UNIT_PRICE");
estimateMapper.updateEstimate(estimateRequest);
// 견적서 모든 아이템 제거
estimateMapper.deleteEstimateItemList(estimateRequest);
// 견적서 아이템 신규 추가
for (ItemRequest itemRequest : itemList) {
itemRequest.setObjectNo(estimateRequest.getObjectNo());
itemRequest.setPlanNo(estimateRequest.getPlanNo());
itemRequest.setPartAdd(
!StringUtils.isEmpty(itemRequest.getPartAdd()) ? itemRequest.getPartAdd() : "0");
itemRequest.setItemChangeFlg(
!StringUtils.isEmpty(itemRequest.getItemChangeFlg())
? itemRequest.getItemChangeFlg()
: "0");
itemRequest.setUserId(estimateRequest.getUserId());
estimateMapper.insertEstimateItem(itemRequest);
}
}
public void insertEstimateCopy(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"));
}
// [1]. 총 플랜 목록 조회 및 제약조건 처리 (플랜 10개까지만 등록)
PlanRequest planRequest = new PlanRequest();
planRequest.setObjectNo(estimateRequest.getObjectNo());
List<PlanResponse> planList = objectMapper.selectPlanList(planRequest);
if (planList.size() > 9) {
throw new QcastException(
ErrorCode.INTERNAL_SERVER_ERROR, message.getMessage("common.message.plan.save.limit"));
}
List<ItemRequest> itemList = new ArrayList<ItemRequest>();
List<ItemResponse> estimateItemList = estimateMapper.selectEstimateItemList(estimateRequest);
for (ItemResponse itemResponse : estimateItemList) {
ItemRequest itemRequest = new ItemRequest();
itemRequest.setItemId(itemResponse.getItemId());
itemRequest.setAmount(itemResponse.getAmount());
itemList.add(itemRequest);
}
// [2]. 아이템 관련 데이터 셋팅 (복사 시 정가 셋팅)
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);
int j = 1;
for (ItemRequest itemRequest : itemList) {
itemRequest.setDispOrder(String.valueOf(j++));
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.setItemGroup(itemResponse.getItemGroup());
break;
}
}
}
// 견적서 복사
estimateMapper.insertEstimateCopy(estimateRequest);
// 견적서 아이템 복사
for (ItemRequest itemRequest : itemList) {
itemRequest.setObjectNo(estimateRequest.getObjectNo());
itemRequest.setPlanNo(estimateRequest.getCopyPlanNo());
itemRequest.setPartAdd(
!StringUtils.isEmpty(itemRequest.getPartAdd()) ? itemRequest.getPartAdd() : "0");
itemRequest.setItemChangeFlg(
!StringUtils.isEmpty(itemRequest.getItemChangeFlg())
? itemRequest.getItemChangeFlg()
: "0");
itemRequest.setUserId(estimateRequest.getUserId());
estimateMapper.insertEstimateItem(itemRequest);
}
// 도면 복사 (추후 개발 필요)
}
public void selectTotalPriceInfo(EstimateResponse estimateResponse) throws Exception {
BigDecimal totAmount = BigDecimal.ZERO;
BigDecimal totVol = BigDecimal.ZERO;
BigDecimal supplyPrice = BigDecimal.ZERO;
BigDecimal vatPrice = BigDecimal.ZERO;
BigDecimal totPrice = BigDecimal.ZERO;
String estimateType = estimateResponse.getEstimateType();
List<ItemResponse> itemList = estimateResponse.getItemList();
// 주택패키지 단가
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 =
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)));
// YJSS인 경우 (PKG 단가 * 모듈용량) + 패키지 제외상품 총 합산
// YJOD인 경우 모든 아이템의 총 합산
if ("YJSS".equals(estimateType)) {
if ("1".equals(itemResponse.getPkgMaterialFlg())) { // 패키지 제외상품 여부(1)
supplyPrice = supplyPrice.add(salePrice.multiply(amount));
} else {
if ("1".equals(itemResponse.getModuleFlg())) {
totVol = totVol.add(pnowW.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)) {
supplyPrice.add(pkgAsp.multiply(totVol));
}
// 부가세 계산 (10프로)
vatPrice = supplyPrice.multiply(new BigDecimal("0.01"));
// 총 가격 합산 (공급가 + 부가세)
totPrice = totPrice.add(supplyPrice.add(vatPrice));
estimateResponse.setTotAmount(String.valueOf(totAmount.setScale(0, BigDecimal.ROUND_HALF_UP)));
estimateResponse.setTotVol(String.valueOf(totVol.setScale(0, BigDecimal.ROUND_HALF_UP)));
estimateResponse.setSupplyPrice(
String.valueOf(supplyPrice.setScale(0, BigDecimal.ROUND_HALF_UP)));
estimateResponse.setVatPrice(String.valueOf(vatPrice.setScale(0, BigDecimal.ROUND_HALF_UP)));
estimateResponse.setTotPrice(String.valueOf(totPrice.setScale(0, BigDecimal.ROUND_HALF_UP)));
}
}