견적서 QSP 연동 API 개발

This commit is contained in:
LAPTOP-L3VE7KK2\USER 2024-11-11 17:37:09 +09:00
parent 0183cbf4c0
commit 282fa9bfb0
10 changed files with 317 additions and 17 deletions

View File

@ -22,14 +22,14 @@ public class EstimateController {
@Operation(description = "1차점 가격 관리 목록을 조회한다.")
@GetMapping("/price/store-price-list")
@ResponseStatus(HttpStatus.OK)
public PriceResponse selectStorePriceList(PriceRequest priceRequest) throws Exception {
public EstimateApiResponse selectStorePriceList(PriceRequest priceRequest) throws Exception {
return estimateService.selectStorePriceList(priceRequest);
}
@Operation(description = "아이템 가격 목록을 조회한다.")
@PostMapping("/price/item-price-list")
@ResponseStatus(HttpStatus.OK)
public PriceResponse selectItemPriceList(@RequestBody PriceRequest priceRequest)
public EstimateApiResponse selectItemPriceList(@RequestBody PriceRequest priceRequest)
throws Exception {
return estimateService.selectItemPriceList(priceRequest);
}

View File

@ -1,7 +1,6 @@
package com.interplug.qcast.biz.estimate;
import com.interplug.qcast.biz.estimate.dto.*;
import com.interplug.qcast.biz.object.dto.*;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
@ -13,6 +12,9 @@ public interface EstimateMapper {
// 견적서 PDF 상세 확인
public EstimateResponse selectEstimatePdfDetail(EstimateRequest estimateRequest);
// 견적서 API 상세 확인
public EstimateSendResponse selectEstimateApiDetail(EstimateRequest estimateRequest);
// 견적서 아이템 목록 조회
public List<ItemResponse> selectEstimateItemList(EstimateRequest estimateRequest);
@ -31,6 +33,9 @@ public interface EstimateMapper {
// 견적서 정보 수정
public int updateEstimate(EstimateRequest estimateRequest);
// 견적서 API 정보 수정
public int updateEstimateApi(EstimateRequest estimateRequest);
// 견적서 지붕재 등록
public int insertEstimateRoof(RoofRequest roofRequest);

View File

@ -21,7 +21,6 @@ import com.interplug.qcast.util.InterfaceQsp;
import io.micrometer.common.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.awt.*;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
@ -62,13 +61,13 @@ public class EstimateService {
@Autowired private PwrGnrSimService pwrGnrSimService;
/**
* 1차점 price 관리 목록 조회
* QSP 1차점 price 관리 목록 조회
*
* @param priceRequest 1차점 price 관련 정보
* @return PriceResponse 1차점 price 목록
* @throws Exception
*/
public PriceResponse selectStorePriceList(PriceRequest priceRequest) throws Exception {
public EstimateApiResponse selectStorePriceList(PriceRequest priceRequest) throws Exception {
// Validation
if (StringUtils.isEmpty(priceRequest.getSaleStoreId())) {
throw new QcastException(
@ -86,7 +85,7 @@ public class EstimateService {
message.getMessage("common.message.required.data", "Estimate Type"));
}
PriceResponse response = null;
EstimateApiResponse response = null;
/* [1]. QSP API (url + param) Setting */
String url = QSP_API_URL + "/api/price/storePriceList";
String apiUrl =
@ -104,7 +103,7 @@ public class EstimateService {
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);
response = om.readValue(strResponse, EstimateApiResponse.class);
} else {
// [msg] No data
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
@ -114,11 +113,13 @@ public class EstimateService {
}
/**
* QSP 아이템 가격 목록 조회
*
* @param priceRequest
* @return PriceResponse
* @throws Exception
*/
public PriceResponse selectItemPriceList(PriceRequest priceRequest) throws Exception {
public EstimateApiResponse selectItemPriceList(PriceRequest priceRequest) throws Exception {
// Validation
if (StringUtils.isEmpty(priceRequest.getSaleStoreId())) {
throw new QcastException(
@ -136,7 +137,7 @@ public class EstimateService {
message.getMessage("common.message.required.data", "Price Code"));
}
PriceResponse response = null;
EstimateApiResponse response = null;
/* [1]. QSP API CALL -> Response */
String strResponse =
interfaceQsp.callApi(
@ -146,7 +147,7 @@ public class EstimateService {
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);
response = om.readValue(strResponse, EstimateApiResponse.class);
} else {
// [msg] No data
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
@ -488,9 +489,11 @@ public class EstimateService {
estimateMapper.deleteEstimateItemList(estimateRequest);
// 견적서 아이템 신규 추가
int j = 1;
for (ItemRequest itemRequest : itemList) {
itemRequest.setObjectNo(estimateRequest.getObjectNo());
itemRequest.setPlanNo(estimateRequest.getPlanNo());
itemRequest.setDispOrder(String.valueOf(j++));
itemRequest.setPartAdd(
!StringUtils.isEmpty(itemRequest.getPartAdd()) ? itemRequest.getPartAdd() : "0");
itemRequest.setItemChangeFlg(
@ -501,6 +504,19 @@ public class EstimateService {
estimateMapper.insertEstimateItem(itemRequest);
}
// 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();
}
@ -717,6 +733,14 @@ public class EstimateService {
}
}
/**
* 아이템 목록을 통한 견적서 가격 자동계산
*
* @param estimateResponse 견적서 정보
* @param itemList 아이템 정보 목록
* @param unitPriceFlg 가격 표시 코드
* @throws Exception
*/
public void selectTotalPriceInfo(
EstimateResponse estimateResponse, List<ItemResponse> itemList, String unitPriceFlg)
throws Exception {
@ -791,7 +815,7 @@ public class EstimateService {
}
// 부가세 계산 (10프로)
vatPrice = supplyPrice.multiply(new BigDecimal("0.01"));
vatPrice = supplyPrice.multiply(new BigDecimal("0.1"));
// 가격 합산 (공급가 + 부가세)
totPrice = totPrice.add(supplyPrice.add(vatPrice));
@ -807,6 +831,86 @@ public class EstimateService {
estimateResponse.setTotPrice(String.valueOf(totPrice.setScale(0, BigDecimal.ROUND_HALF_UP)));
}
/**
* 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 = "";
// 견적서 상세 조회
EstimateSendResponse estimateSendResponse =
estimateMapper.selectEstimateApiDetail(estimateRequest);
if (estimateSendResponse == null) {
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
} else {
estimateSendResponse.setSaveType("3");
estimateSendResponse.setSyncFlg("0");
estimateSendResponse.setConstructSpecification(
!StringUtils.isEmpty(estimateRequest.getConstructSpecification())
? estimateRequest.getConstructSpecification().split("")[0]
: "");
estimateSendResponse.setDelFlg("1".equals(estimateSendResponse.getDelFlg()) ? "Y" : "N");
// 아이템 목록 조회
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);
}
EstimateApiResponse response = null;
/* [1]. QSP API CALL -> Response */
String strResponse =
interfaceQsp.callApi(
HttpMethod.POST, QSP_API_URL + "/api/master/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);
Map<String, Object> result = (Map<String, Object>) response.getData();
if (result != null) {
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("1");
data.setDocNo(String.valueOf(succ.get("docNo")));
}
}
}
}
}
} else {
log.error("sendEstimateApi >>> " + message.getMessage("common.message.no.data"));
}
return quoteList;
}
public Map<String, Object> convertVoToMap(Object vo) {
Map<String, Object> result = new HashMap<String, Object>();

View File

@ -3,7 +3,7 @@ package com.interplug.qcast.biz.estimate.dto;
import lombok.Data;
@Data
public class PriceResponse {
public class EstimateApiResponse {
/** API response result */
private Object result;

View File

@ -150,6 +150,9 @@ public class EstimateRequest {
@Schema(description = "가격코드")
private String priceCd;
@Schema(description = "QSP 동기화 여부")
private String syncFlg;
@Schema(description = "비고")
private String remarks;

View File

@ -0,0 +1,11 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
@Data
public class EstimateSendRequest {
@Schema(description = "견적서 목록 정보")
List<EstimateSendResponse> quoteList;
}

View File

@ -0,0 +1,115 @@
package com.interplug.qcast.biz.estimate.dto;
import com.interplug.qcast.biz.file.dto.FileResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
@Data
public class EstimateSendResponse {
@Schema(description = "물건번호")
private String objectNo;
@Schema(description = "플랜번호")
private String planNo;
@Schema(description = "판매점 ID")
private String saleStoreId;
@Schema(description = "물건명")
private String objectName;
@Schema(description = "견적서 등록일")
private String estimateDetailCreateDate;
@Schema(description = "수취회사명")
private String receiveCompanyName;
@Schema(description = "수취자명")
private String receiveUser;
@Schema(description = "배송지 우편번호")
private String deliveryZipNo;
@Schema(description = "배송지 주소")
private String deliveryTarget;
@Schema(description = "배송지 연락처")
private String deliveryTel;
@Schema(description = "배송 희망일")
private String deliveryHopeDate;
@Schema(description = "사양확장일")
private String specificationConfirmDate;
@Schema(description = "결제기간일")
private String paymentTerms;
@Schema(description = "차종류 코드")
private String carKindCd;
@Schema(description = "Track 종류 코드")
private String trackKind;
@Schema(description = "Track 10톤 배송일")
private String track10tDelivery;
@Schema(description = "Track 무게 코드")
private String trackWeight;
@Schema(description = "Track 시간 지정")
private String trackTimeSpecify;
@Schema(description = "Track 시간")
private String trackTime;
@Schema(description = "포리프트 여부")
private String forklift;
@Schema(description = "전압여부 (주택:0, 저압:1)")
private String houseClassCd;
@Schema(description = "영업사원 코드")
private String businessChargerCd;
@Schema(description = "영업사원 그룹 코드")
private String businessGroupCd;
@Schema(description = "시공방법")
private String constructSpecification;
@Schema(description = "북면설치여부")
private String northArrangement;
@Schema(description = "견적서 타입 (YJSS, YJOD)")
private String estimateType;
@Schema(description = "주택패키지 단가")
private String pkgAsp;
@Schema(description = "삭제여부")
private String delFlg;
@Schema(description = "마지막 수정일")
private String lastEditDatetime;
@Schema(description = "마지막 수정자")
private String lastEditUser;
@Schema(description = "저장타입(3:Q.CAST III)")
private String saveType;
@Schema(description = "문서번호")
private String docNo;
@Schema(description = "동기화 처리여부")
private String syncFlg;
// 데이터 목록 관련 정보
@Schema(description = "아이템 목록")
List<ItemResponse> itemList;
@Schema(description = "첨부파일 목록")
List<FileResponse> fileList;
}

View File

@ -116,9 +116,12 @@ public class ObjectRequest {
@Schema(description = "검색 - 판매점ID")
private String schSaleStoreId;
@Schema(description = "검색 - 선택판매점ID")
@Schema(description = "검색 - 선택판매점 1차점 ID")
private String schSelSaleStoreId;
@Schema(description = "검색 - 선택판매점 2차점 ID")
private String schOtherSelSaleStoreId;
@Schema(description = "검색 - 주소")
private String schAddress;

View File

@ -106,6 +106,48 @@
ON T.CREATE_SALE_STORE_ID = SS2.SALE_STORE_ID
</select>
<select id="selectEstimateApiDetail" parameterType="com.interplug.qcast.biz.estimate.dto.EstimateRequest" resultType="com.interplug.qcast.biz.estimate.dto.EstimateSendResponse">
/* sqlid : com.interplug.qcast.biz.estimate.selectEstimateDetail */
SELECT
O.OBJECT_NO
, O.SALE_STORE_ID
, O.OBJECT_NAME
, O.RECEIVE_COMPANY_NAME
, O.RECEIVE_USER
, O.DELIVERY_ZIP_NO
, O.DELIVERY_TARGET
, O.DELIVERY_TEL
, O.DELIVERY_HOPE_DATE
, O.SPECIFICATION_CONFIRM_DATE
, O.PAYMENT_TERMS
, O.CAR_KIND_CD
, O.TRACK_KAIND AS TRACK_KIND
, O.TRACK_10T_DELIVERY
, O.TRACK_WEIGHT
, O.TRACK_TIME_SPECIFY
, O.TRACK_TIME
, O.FORKLIFT
, O.HOUSE_CLASS_CD
, O.BUSINESS_CHARGER_CD
, O.BUSINESS_GROUP_CD
, P.PLAN_NO
, P.CONSTRUCT_SPECIFICATION
, P.NORTH_ARRANGEMENT
, P.ESTIMATE_TYPE
, P.PKG_ASP
, P.DEL_FLG
, CONVERT(NVARCHAR(10), P.CREATE_DATETIME, 121) AS ESTIMATE_DETAIL_CREATE_DATE
, P.LAST_EDIT_DATETIME
, P.LAST_EDIT_USER
FROM T_PLAN P WITH (NOLOCK)
INNER JOIN T_OBJECT O WITH (NOLOCK)
ON P.OBJECT_NO = O.OBJECT_NO
INNER JOIN M_SALES_STORE SS WITH(NOLOCK)
ON O.SALE_STORE_ID = SS.SALE_STORE_ID
WHERE P.OBJECT_NO = #{objectNo}
AND P.PLAN_NO = #{planNo}
</select>
<select id="selectEstimateItemList" parameterType="com.interplug.qcast.biz.estimate.dto.EstimateRequest" resultType="com.interplug.qcast.biz.estimate.dto.ItemResponse">
/* sqlid : com.interplug.qcast.biz.estimate.selectEstimateItemList */
SELECT
@ -281,6 +323,16 @@
AND PLAN_NO = #{planNo}
</update>
<update id="updateEstimateApi" parameterType="com.interplug.qcast.biz.estimate.dto.EstimateRequest">
/* sqlid : com.interplug.qcast.biz.estimate.updateEstimateApi */
UPDATE T_PLAN
SET
DOC_NO = #{docNo}
, SYNC_FLG = #{syncFlg}
WHERE OBJECT_NO = #{objectNo}
AND PLAN_NO = #{planNo}
</update>
<insert id="insertEstimateItem" parameterType="com.interplug.qcast.biz.estimate.dto.ItemRequest">
/* sqlid : com.interplug.qcast.biz.estimate.insertEstimateItem */
INSERT INTO T_PART_ESTIMATE

View File

@ -220,9 +220,16 @@
<if test='schSaleStoreId != null and schSaleStoreId != ""'>
AND O.SALE_STORE_ID LIKE '%' + #{schSaleStoreId} + '%'
</if>
<if test='schSelSaleStoreId != null and schSelSaleStoreId != ""'>
AND O.SALE_STORE_ID = #{schSelSaleStoreId}
</if>
<choose>
<when test='schOtherSelSaleStoreId != null and schOtherSelSaleStoreId != ""'>
/* 2차점까지 고름 */
AND O.SALE_STORE_ID = #{schOtherSelSaleStoreId}
</when>
<when test='schSelSaleStoreId != null and schSelSaleStoreId != ""'>
/* 1차점까지만 고름 */
AND O.SALE_STORE_ID = #{schSelSaleStoreId}
</when>
</choose>
<if test='schAddress != null and schAddress != ""'>
AND O.ADDRESS LIKE '%' + #{schAddress} + '%'
</if>