diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemController.java b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemController.java index cb5993e7..a5da9ee9 100644 --- a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemController.java +++ b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemController.java @@ -1,8 +1,10 @@ package com.interplug.qcast.biz.displayItem; import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; +import com.interplug.qcast.biz.displayItem.dto.ItemResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -23,4 +25,19 @@ public class DisplayItemController { throws Exception { displayItemService.setStoreDisplayItemSave(displayItemRequest); } + + @Operation(description = "제품 목록을 조회한다.") + @GetMapping("/item_list") + @ResponseStatus(HttpStatus.OK) + public List getItemList(@RequestParam("saleStoreId") String saleStoreId) + throws Exception { + return displayItemService.getItemList(saleStoreId); + } + + @Operation(description = "제품 상세 정보를 조회한다.") + @GetMapping("/item_detail") + @ResponseStatus(HttpStatus.OK) + public ItemResponse getItemDetail(@RequestParam("itemId") String itemId) throws Exception { + return displayItemService.getItemDetail(itemId); + } } diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java index 9c1bf003..59244c97 100644 --- a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java +++ b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java @@ -1,10 +1,17 @@ package com.interplug.qcast.biz.displayItem; import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; +import com.interplug.qcast.biz.displayItem.dto.ItemResponse; +import java.util.List; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; @Mapper public interface DisplayItemMapper { void setStoreDisplayItemSave(DisplayItemRequest displayItemRequest) throws Exception; + + List getItemList(@Param("saleStoreId") String saleStoreId); + + ItemResponse getItemDetail(@Param("itemId") String itemId); } diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java index c74ad7aa..01a5c442 100644 --- a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java +++ b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java @@ -1,6 +1,8 @@ package com.interplug.qcast.biz.displayItem; import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; +import com.interplug.qcast.biz.displayItem.dto.ItemResponse; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -15,4 +17,12 @@ public class DisplayItemService { public void setStoreDisplayItemSave(DisplayItemRequest displayItemRequest) throws Exception { displayItemMapper.setStoreDisplayItemSave(displayItemRequest); } + + public List getItemList(String saleStoreId) { + return displayItemMapper.getItemList(saleStoreId); + } + + public ItemResponse getItemDetail(String itemId) { + return displayItemMapper.getItemDetail(itemId); + } } diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/dto/ItemResponse.java b/src/main/java/com/interplug/qcast/biz/displayItem/dto/ItemResponse.java new file mode 100644 index 00000000..740f94d2 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/displayItem/dto/ItemResponse.java @@ -0,0 +1,41 @@ +package com.interplug.qcast.biz.displayItem.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class ItemResponse { + + @Schema(description = "Itme Id") + private String itemId; + + @Schema(description = "Item Name") + private String itemName; + + @Schema(description = "Goods No") + private String goodsNo; + + @Schema(description = "Unit") + private String unit; + + @Schema(description = "Specification") + private String specification; + + @Schema(description = "pnow_w") + private String pnowW; + + @Schema(description = "Item Group") + private String itemGroup; + + @Schema(description = "Module Flag") + private String moduleFlg; + + @Schema(description = "PKG Material Flag") + private String pkgMaterialFlg; + + @Schema(description = "File Upload Flag") + private String fileUploadFlg; + + @Schema(description = "Sale Price") + private String salePrice; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/EstimateController.java b/src/main/java/com/interplug/qcast/biz/estimate/EstimateController.java new file mode 100644 index 00000000..998f9a89 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/EstimateController.java @@ -0,0 +1,52 @@ +package com.interplug.qcast.biz.estimate; + +import com.interplug.qcast.biz.estimate.dto.EstimateRequest; +import com.interplug.qcast.biz.estimate.dto.EstimateResponse; +import com.interplug.qcast.biz.estimate.dto.PriceRequest; +import com.interplug.qcast.biz.estimate.dto.PriceResponse; +import com.interplug.qcast.biz.object.dto.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@RequestMapping("/api/estimate") +@RequiredArgsConstructor +@Tag(name = "EstimateController", description = "견적서 관련 API") +public class EstimateController { + private final EstimateService estimateService; + + @Operation(description = "1차점 가격 관리 목록을 조회한다.") + @GetMapping("/price/store-price-list") + @ResponseStatus(HttpStatus.OK) + public PriceResponse 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) + throws Exception { + return estimateService.selectItemPriceList(priceRequest); + } + + @Operation(description = "견적서 상세를 조회한다.") + @GetMapping("/{objectNo}/{planNo}/detail") + @ResponseStatus(HttpStatus.OK) + public EstimateResponse selectObjectDetail( + @PathVariable String objectNo, @PathVariable String planNo) throws Exception { + return estimateService.selectEstimateDetail(objectNo, planNo); + } + + @Operation(description = "견적서를 저장한다.") + @PostMapping("/save-estimate") + @ResponseStatus(HttpStatus.CREATED) + public void insertObject(@RequestBody EstimateRequest estimateRequest) throws Exception { + estimateService.insertEstimate(estimateRequest); + } +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/EstimateMapper.java b/src/main/java/com/interplug/qcast/biz/estimate/EstimateMapper.java new file mode 100644 index 00000000..3972bc7f --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/EstimateMapper.java @@ -0,0 +1,30 @@ +package com.interplug.qcast.biz.estimate; + +import com.interplug.qcast.biz.estimate.dto.EstimateRequest; +import com.interplug.qcast.biz.estimate.dto.EstimateResponse; +import com.interplug.qcast.biz.estimate.dto.ItemRequest; +import com.interplug.qcast.biz.estimate.dto.ItemResponse; +import com.interplug.qcast.biz.object.dto.*; +import java.util.List; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface EstimateMapper { + // 견적서 상세 확인 + public EstimateResponse selectEstimateDetail(EstimateRequest estimateRequest); + + // 견적서 아이템 목록 조회 + public List selectEstimateItemList(EstimateRequest estimateRequest); + + // 아이템 마스터 목록 조회 + public List selectItemMasterList(EstimateRequest estimateRequest); + + // 견적서 정보 수정 + public int updateEstimate(EstimateRequest estimateRequest); + + // 견적서 아이템 등록 + public int insertEstimateItem(ItemRequest itemRequest); + + // 견적서 아이템 목록 삭제(물리 삭제) + public int deleteEstimateItemList(EstimateRequest estimateRequest); +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java b/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java new file mode 100644 index 00000000..c3d8494f --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java @@ -0,0 +1,421 @@ +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.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.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 itemList = estimateMapper.selectEstimateItemList(estimateRequest); + response.setItemList(itemList); + + // 총 합산금액 계산 + this.selectTotalPriceInfo(response); + + // 첨부파일 목록 조회 + FileRequest fileDeleteReq = new FileRequest(); + fileDeleteReq.setObjectNo(objectNo); + fileDeleteReq.setCategory("10"); + fileDeleteReq.setPlanNo(planNo); + + List 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 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 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 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.setSalePrice(itemResponse.getSalePrice()); + itemRequest.setPkgMaterialFlg(itemResponse.getPkgMaterialFlg()); + itemRequest.setItemGroup(itemResponse.getItemGroup()); + + break; + } + } + } + } + + // 아아템 목록 필수 값 체크 + 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); + + // 견적서 정보 수정 + 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 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 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))); + } +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateRequest.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateRequest.java new file mode 100644 index 00000000..cb385e5d --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateRequest.java @@ -0,0 +1,153 @@ +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 EstimateRequest { + @Schema(description = "물건번호") + private String objectNo; + + @Schema(description = "플랜번호") + private String planNo; + + @Schema(description = "판매점ID") + private String saleStoreId; + + @Schema(description = "SAP 판매점코드") + private String sapSalesStoreCd; + + @Schema(description = "시공방법") + private String constructSpecification; + + @Schema(description = "설치높이") + private String setupHeight; + + @Schema(description = "날씨포인트") + private String weatherPoint; + + @Schema(description = "날씨포인트") + private String roofKindId; + + @Schema(description = "경사") + private String slope; + + @Schema(description = "지붕재 아이템 CLASS ID") + private String roofMaterialClassId; + + @Schema(description = "지붕재 아이템 ID") + private String roofMaterialId; + + @Schema(description = "가대 설치 ID") + private String supportMethodId; + + @Schema(description = "모델") + private String moduleModel; + + @Schema(description = "담당자") + private String charger; + + @Schema(description = "견적서 유효기간") + private String estimateValidityTerm; + + @Schema(description = "결정 플랜") + private String decisionPlan; + + @Schema(description = "넘버") + private String number; + + @Schema(description = "시스템용량") + private String capacity; + + @Schema(description = "강설량") + private String snowfall; + + @Schema(description = "표준풍속검사") + private String standardWindSpeedCheck; + + @Schema(description = "옵션커버") + private String optionCover; + + @Schema(description = "한화여부") + private String hanwfaFlg; + + @Schema(description = "기준종류ID") + private String standKindId; + + @Schema(description = "기준풍속ID") + private String standardWindSpeedId; + + @Schema(description = "가대 메이커") + private String supportMeaker; + + @Schema(description = "소비세ID") + private String consumptionTaxId; + + @Schema(description = "상태코드") + private String status; + + @Schema(description = "사용자아이디") + private String userId; + + @Schema(description = "삭제여부") + private String delFlg; + + @Schema(description = "파워컨디셔너") + private String pcTypeNo; + + @Schema(description = "북면설치여부") + private String northArrangement; + + @Schema(description = "지붕재") + private String roofMaterialIdMulti; + + @Schema(description = "가대") + private String supportMethodIdMulti; + + @Schema(description = "가대 메이커") + private String supportMeakerMulti; + + @Schema(description = "다른 지붕재여부") + private String diffRoofEnabled; + + @Schema(description = "발주여부") + private String orderFlg; + + @Schema(description = "도면저장여부") + private String drawingFlg; + + @Schema(description = "견적일") + private String estimateDate; + + @Schema(description = "견적서번호") + private String docNo; + + @Schema(description = "견적서타입") + private String estimateType; + + @Schema(description = "후일자료제출") + private String fileFlg; + + @Schema(description = "견적서 특이사항") + private String estimateOption; + + @Schema(description = "PKG 단가") + private String pkgAsp; + + @Schema(description = "가격코드") + private String priceCd; + + @Schema(description = "비고") + private String remarks; + + @Schema(description = "아이템번호 목록") + private String[] arrItemId; + + // 데이터 목록 관련 정보 + @Schema(description = "지붕재 목록") + List roofList; + + @Schema(description = "아이템 목록") + List itemList; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateResponse.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateResponse.java new file mode 100644 index 00000000..8e15bcc0 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateResponse.java @@ -0,0 +1,162 @@ +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 EstimateResponse { + @Schema(description = "물건번호") + private String objectNo; + + @Schema(description = "플랜번호") + private String planNo; + + @Schema(description = "시공방법") + private String constructSpecification; + + @Schema(description = "설치높이") + private String setupHeight; + + @Schema(description = "날씨포인트") + private String weatherPoint; + + @Schema(description = "날씨포인트") + private String roofKindId; + + @Schema(description = "경사") + private String slope; + + @Schema(description = "지붕재 아이템 CLASS ID") + private String roofMaterialClassId; + + @Schema(description = "지붕재 아이템 ID") + private String roofMaterialId; + + @Schema(description = "가대 설치 ID") + private String supportMethodId; + + @Schema(description = "모델") + private String moduleModel; + + @Schema(description = "담당자") + private String charger; + + @Schema(description = "견적서 유효기간") + private String estimateValidityTerm; + + @Schema(description = "결정 플랜") + private String decisionPlan; + + @Schema(description = "넘버") + private String number; + + @Schema(description = "시스템용량") + private String capacity; + + @Schema(description = "강설량") + private String snowfall; + + @Schema(description = "표준풍속검사") + private String standardWindSpeedCheck; + + @Schema(description = "옵션커버") + private String optionCover; + + @Schema(description = "한화여부") + private String hanwfaFlg; + + @Schema(description = "기준종류ID") + private String standKindId; + + @Schema(description = "기준풍속ID") + private String standardWindSpeedId; + + @Schema(description = "가대 메이커") + private String supportMeaker; + + @Schema(description = "소비세ID") + private String consumptionTaxId; + + @Schema(description = "상태코드") + private String status; + + @Schema(description = "사용자아이디") + private String userId; + + @Schema(description = "삭제여부") + private String delFlg; + + @Schema(description = "파워컨디셔너") + private String pcTypeNo; + + @Schema(description = "북면설치여부") + private String northArrangement; + + @Schema(description = "지붕재") + private String roofMaterialIdMulti; + + @Schema(description = "가대") + private String supportMethodIdMulti; + + @Schema(description = "가대 메이커") + private String supportMeakerMulti; + + @Schema(description = "다른 지붕재여부") + private String diffRoofEnabled; + + @Schema(description = "견적일") + private String estimateDate; + + @Schema(description = "발주여부") + private String orderFlg; + + @Schema(description = "견적서번호") + private String docNo; + + @Schema(description = "견적서타입") + private String estimateType; + + @Schema(description = "후일자료제출") + private String fileFlg; + + @Schema(description = "견적서 특이사항") + private String estimateOption; + + @Schema(description = "PKG 단가") + private String pkgAsp; + + @Schema(description = "가격코드") + private String priceCd; + + // 가격 관련 정보 + @Schema(description = "총 수량") + private String totAmount; + + @Schema(description = "총 용량") + private String totVol; + + @Schema(description = "공급가액") + private String supplyPrice; + + @Schema(description = "부가세") + private String vatPrice; + + @Schema(description = "총액") + private String totPrice; + + // 물건정보 정보 + @Schema(description = "물건명") + private String objectName; + + @Schema(description = "경칭") + private String objectNameOmit; + + // 데이터 목록 관련 정보 + @Schema(description = "아이템 목록") + List itemList; + + @Schema(description = "첨부파일 목록") + List fileList; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/ItemRequest.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/ItemRequest.java new file mode 100644 index 00000000..71f3ac1a --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/ItemRequest.java @@ -0,0 +1,61 @@ +package com.interplug.qcast.biz.estimate.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +// @Data +@Getter +@Setter +public class ItemRequest { + @Schema(description = "물건번호") + private String objectNo; + + @Schema(description = "플랜번호") + private String planNo; + + @Schema(description = "아이템 ID") + private String itemId; + + @Schema(description = "정렬순서") + private String dispOrder; + + @Schema(description = "아이템 번호") + private String itemNo; + + @Schema(description = "아이템명") + private String itemName; + + @Schema(description = "단위") + private String unit; + + @Schema(description = "용량") + private String specification; + + @Schema(description = "수량") + private String amount; + + @Schema(description = "변경수량") + private String amountChange; + + @Schema(description = "추가구분코드") + private String partAdd; + + @Schema(description = "단가") + private String salePrice; + + @Schema(description = "PKG 제외상품 여부") + private String pkgMaterialFlg; + + @Schema(description = "아이템 변경 여부") + private String itemChangeFlg; + + @Schema(description = "W") + private String pnowW; + + @Schema(description = "아이템 그룹코드") + private String itemGroup; + + @Schema(description = "사용자아이디") + private String userId; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/ItemResponse.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/ItemResponse.java new file mode 100644 index 00000000..d9eafc56 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/ItemResponse.java @@ -0,0 +1,58 @@ +package com.interplug.qcast.biz.estimate.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +// @Data +@Getter +@Setter +public class ItemResponse { + @Schema(description = "물건번호") + private String objectNo; + + @Schema(description = "플랜번호") + private String planNo; + + @Schema(description = "아이템 ID") + private String itemId; + + @Schema(description = "아이템 번호") + private String itemNo; + + @Schema(description = "아이템명") + private String itemName; + + @Schema(description = "단위") + private String unit; + + @Schema(description = "용량") + private String specification; + + @Schema(description = "수량") + private String amount; + + @Schema(description = "단가") + private String salePrice; + + @Schema(description = "합산") + private String saleTotPrice; + + @Schema(description = "PKG 제외상품 여부") + private String pkgMaterialFlg; + + @Schema(description = "아이템 변경 여부") + private String itemChangeFlg; + + @Schema(description = "W") + private String pnowW; + + @Schema(description = "아이템 그룹코드") + private String itemGroup; + + @Schema(description = "파일첨부 필수여부") + private String fileUploadFlg; + + @Schema(description = "모듈여부") + private String moduleFlg; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceItemRequest.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceItemRequest.java new file mode 100644 index 00000000..7e1d506b --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceItemRequest.java @@ -0,0 +1,16 @@ +package com.interplug.qcast.biz.estimate.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +// @Data +@Getter +@Setter +public class PriceItemRequest { + @Schema(description = "Item ID") + private String itemId; + + @Schema(description = "BOM Item ID") + private String bomItemId; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceRequest.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceRequest.java new file mode 100644 index 00000000..4a295607 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceRequest.java @@ -0,0 +1,26 @@ +package com.interplug.qcast.biz.estimate.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +// @Data +@Getter +@Setter +public class PriceRequest { + @Schema(description = "판매점ID") + private String saleStoreId; + + @Schema(description = "SAP 판매점코드") + private String sapSalesStoreCd; + + @Schema(description = "견적구분") + private String docTpCd; + + @Schema(description = "가격조회코드") + private String priceCd; + + @Schema(description = "아이템번호 목록") + private List itemIdList; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceResponse.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceResponse.java new file mode 100644 index 00000000..01fbde27 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/PriceResponse.java @@ -0,0 +1,15 @@ +package com.interplug.qcast.biz.estimate.dto; + +import lombok.Data; + +@Data +public class PriceResponse { + /** API response result */ + private Object result; + + /** API response data */ + private Object data; + + /** API response data */ + private Object data2; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/RoofRequest.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/RoofRequest.java new file mode 100644 index 00000000..091b4e0f --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/RoofRequest.java @@ -0,0 +1,28 @@ +package com.interplug.qcast.biz.estimate.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +// @Data +@Getter +@Setter +public class RoofRequest { + @Schema(description = "지붕재 아이템 ID") + private String roofMaterialId; + + @Schema(description = "공법 ID") + private String supportMethodId; + + @Schema(description = "시공사양 ID") + private String constructSpecification; + + @Schema(description = "지붕재 아이템명") + private String roofMaterialIdMulti; + + @Schema(description = "공법명") + private String supportMethodIdMulti; + + @Schema(description = "가대메이커명") + private String supportMeaker; +} diff --git a/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownController.java b/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownController.java index f583b441..957ea896 100644 --- a/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownController.java +++ b/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownController.java @@ -64,9 +64,9 @@ public class ExcelDownController { @Operation(description = "과거데이터_보증서발행완료 물건 파일 다운로드 조회") @PostMapping("/wrnt-isnc-cmpl-file-down") - @ResponseStatus(HttpStatus.OK) - public void warrantyIssuedCmpFileDown(@RequestBody WrntIsncCmplRequest wrntIsncCmplRequest, - HttpServletResponse response) throws Exception { + public void warrantyIssuedCmpFileDown( + @RequestBody WrntIsncCmplRequest wrntIsncCmplRequest, HttpServletResponse response) + throws Exception { try { excelDownService.selectWarrantyIssuedCmpFileData(wrntIsncCmplRequest, response); } catch (Exception e) { diff --git a/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownService.java b/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownService.java index 9b800124..e6535d63 100644 --- a/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownService.java +++ b/src/main/java/com/interplug/qcast/biz/excelDown/ExcelDownService.java @@ -1,8 +1,6 @@ package com.interplug.qcast.biz.excelDown; import com.interplug.qcast.biz.excelDown.dto.*; -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.ZipFileManager; import jakarta.servlet.http.HttpServletResponse; @@ -66,9 +64,12 @@ public class ExcelDownService { } zipFileManager.createZipFile(response, "Warranty-issued-completed-files", listFile); + } else { - throw new QcastException( - ErrorCode.NOT_FOUND, message.getMessage("common.message.no.dataDown")); + // 데이터가 없을 경우 NO_CONTENT 상태 코드 설정 후 종료 + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + response.getWriter().write(message.getMessage("common.message.no.dataDown")); + response.flushBuffer(); } } } diff --git a/src/main/java/com/interplug/qcast/biz/login/dto/UserResponse.java b/src/main/java/com/interplug/qcast/biz/login/dto/UserResponse.java index c5a2a338..b6cd3e48 100644 --- a/src/main/java/com/interplug/qcast/biz/login/dto/UserResponse.java +++ b/src/main/java/com/interplug/qcast/biz/login/dto/UserResponse.java @@ -24,5 +24,5 @@ public class UserResponse { private String pwdInitYn; // Password Init Yn private String storeLvl; // Store Level private String groupId; // groupId - + private String custCd; // custCd } diff --git a/src/main/java/com/interplug/qcast/biz/object/ObjectController.java b/src/main/java/com/interplug/qcast/biz/object/ObjectController.java index 58aa5027..afbdfc82 100644 --- a/src/main/java/com/interplug/qcast/biz/object/ObjectController.java +++ b/src/main/java/com/interplug/qcast/biz/object/ObjectController.java @@ -1,15 +1,31 @@ package com.interplug.qcast.biz.object; -import com.interplug.qcast.biz.object.dto.*; +import java.util.List; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import com.interplug.qcast.biz.object.dto.ObjectRequest; +import com.interplug.qcast.biz.object.dto.ObjectResponse; +import com.interplug.qcast.biz.object.dto.PlanReqRequest; +import com.interplug.qcast.biz.object.dto.PlanReqResponse; +import com.interplug.qcast.biz.object.dto.PlanRequest; +import com.interplug.qcast.biz.object.dto.PrefResponse; +import com.interplug.qcast.biz.object.dto.SaleStoreResponse; +import com.interplug.qcast.biz.object.dto.UploadRequest; +import com.interplug.qcast.biz.object.dto.WindSpeedResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.*; @Slf4j @RestController @@ -17,7 +33,7 @@ import org.springframework.web.bind.annotation.*; @RequiredArgsConstructor @Tag(name = "ObjectController", description = "물건정보 관련 API") public class ObjectController { - // @Autowired private ObjectService objectService; + // @Autowired private ObjectService objectService; private final ObjectService objectService; @Operation(description = "물건정보 도도부현을 조회한다.") @@ -44,9 +60,9 @@ public class ObjectController { @Operation(description = "판매점 목록을 조회한다.") @GetMapping("/saleStore/{saleStoreId}/list") @ResponseStatus(HttpStatus.OK) - public List selectSaleStoreList(@PathVariable String saleStoreId) - throws Exception { - return objectService.selectSaleStoreList(saleStoreId); + public List selectSaleStoreList(@PathVariable String saleStoreId, + String userId) throws Exception { + return objectService.selectSaleStoreList(saleStoreId, userId); } @Operation(description = "물건정보 목록을 조회한다.") @@ -115,12 +131,8 @@ public class ObjectController { @Operation(description = "견적서 파일을 다운로드한다.") @PostMapping("/file/{objectNo}/{no}") @ResponseStatus(HttpStatus.OK) - public void fileDownload( - HttpServletRequest request, - HttpServletResponse response, - @PathVariable String objectNo, - @PathVariable String no) - throws Exception { + public void fileDownload(HttpServletRequest request, HttpServletResponse response, + @PathVariable String objectNo, @PathVariable String no) throws Exception { UploadRequest uploadRequest = new UploadRequest(); uploadRequest.setObjectNo(objectNo); diff --git a/src/main/java/com/interplug/qcast/biz/object/ObjectMapper.java b/src/main/java/com/interplug/qcast/biz/object/ObjectMapper.java index 0f8488ee..2c0b0fc5 100644 --- a/src/main/java/com/interplug/qcast/biz/object/ObjectMapper.java +++ b/src/main/java/com/interplug/qcast/biz/object/ObjectMapper.java @@ -5,7 +5,7 @@ import java.util.List; import org.apache.ibatis.annotations.Mapper; @Mapper -interface ObjectMapper { +public interface ObjectMapper { // 도도부현 목록 조회 public List selectPrefList(); diff --git a/src/main/java/com/interplug/qcast/biz/object/ObjectService.java b/src/main/java/com/interplug/qcast/biz/object/ObjectService.java index 6a77a1e1..12045911 100644 --- a/src/main/java/com/interplug/qcast/biz/object/ObjectService.java +++ b/src/main/java/com/interplug/qcast/biz/object/ObjectService.java @@ -1,14 +1,5 @@ package com.interplug.qcast.biz.object; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.interplug.qcast.biz.object.dto.*; -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 jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -17,11 +8,11 @@ import java.net.URLConnection; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Comparator; import java.util.List; import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -29,6 +20,30 @@ import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; import org.springframework.util.FileCopyUtils; import org.springframework.web.util.UriComponentsBuilder; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.interplug.qcast.biz.object.dto.ObjectRequest; +import com.interplug.qcast.biz.object.dto.ObjectResponse; +import com.interplug.qcast.biz.object.dto.PlanReqRequest; +import com.interplug.qcast.biz.object.dto.PlanReqResponse; +import com.interplug.qcast.biz.object.dto.PlanRequest; +import com.interplug.qcast.biz.object.dto.PlanResponse; +import com.interplug.qcast.biz.object.dto.PrefResponse; +import com.interplug.qcast.biz.object.dto.SaleStoreResponse; +import com.interplug.qcast.biz.object.dto.UploadRequest; +import com.interplug.qcast.biz.object.dto.UploadResponse; +import com.interplug.qcast.biz.object.dto.WindSpeedResponse; +import com.interplug.qcast.biz.storeFavorite.StoreFavoriteService; +import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteRequest; +import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteResponse; +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 jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Slf4j @Service @@ -46,6 +61,8 @@ public class ObjectService { private final ObjectMapper objectMapper; + private final StoreFavoriteService storeFavoriteService; + public List selectPrefList() throws Exception { return objectMapper.selectPrefList(); } @@ -58,12 +75,54 @@ public class ObjectService { return objectMapper.selectWindSpeedList(city); } - public List selectSaleStoreList(String saleStoreId) throws Exception { + public List selectSaleStoreList(String saleStoreId, String userId) + throws Exception { + + // [0]. 판매점 목록 조회 + List storeList = new ArrayList(); + if ("T01".equals(saleStoreId)) { - return objectMapper.selectSaleStoreAllList(); + storeList = objectMapper.selectSaleStoreAllList(); + + // [1]. 판매점 목록 조회 결과 + if (storeList.size() > 0) { + StoreFavoriteRequest storeFavoriteReq = new StoreFavoriteRequest(); + storeFavoriteReq.setUserId(userId); + + // [2]. 사용자 판매점 즐겨찾기 목록 조회 (QSP -> QCAST) + StoreFavoriteResponse storeFavoriteRes = new StoreFavoriteResponse(); + storeFavoriteRes = storeFavoriteService.getStoreFavoriteList(storeFavoriteReq); + + List> data = (List>) storeFavoriteRes.getData(); + Map result = (Map) storeFavoriteRes.getResult(); + + // [3]. 판매점 목록 중, 즐겨찾기 판매점에 해당하는 경우 정렬 기준 셋팅 + if ("S".equals(result.get("resultCode"))) { + if (data.size() > 0) { + for (SaleStoreResponse saleStore : storeList) { + String storeId = saleStore.getSaleStoreId(); + saleStore.setPriority("B"); + for (Map storeFavorite : data) { + String favStoreId = (String) storeFavorite.get("storeId"); + if (storeId.equals(favStoreId)) { + saleStore.setPriority("A" + (String) storeFavorite.get("priority")); + } + } + } + // [4]. 정렬 기준 sort (오름차순) + storeList.sort(Comparator.comparing(SaleStoreResponse::getPriority)); + } + } else { + throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, + (String) result.get("resultMsg")); + } + } + } else { - return objectMapper.selectSaleStoreList(saleStoreId); + storeList = objectMapper.selectSaleStoreList(saleStoreId); } + + return storeList; } public SaleStoreResponse selectSaleStoreInfo(String saleStoreId) throws Exception { @@ -335,6 +394,12 @@ public class ObjectService { PlanReqResponse response = null; /* [1]. QSP API (url + param) Setting */ + String encodedSchPlanReqNo = + URLEncoder.encode( + StringUtils.isEmpty(planReqRequest.getSchPlanReqNo()) + ? "" + : planReqRequest.getSchPlanReqNo(), + StandardCharsets.UTF_8); String encodedSchTitle = URLEncoder.encode( StringUtils.isEmpty(planReqRequest.getSchTitle()) ? "" : planReqRequest.getSchTitle(), @@ -345,6 +410,7 @@ public class ObjectService { ? "" : planReqRequest.getSchAddress(), StandardCharsets.UTF_8); + String encodedSchSaleStoreName = URLEncoder.encode( StringUtils.isEmpty(planReqRequest.getSchSaleStoreName()) @@ -359,11 +425,12 @@ public class ObjectService { StandardCharsets.UTF_8); String url = QSP_API_URL + "/api/planReq/list"; + String apiUrl = UriComponentsBuilder.fromHttpUrl(url) .queryParam("saleStoreId", planReqRequest.getSaleStoreId()) .queryParam("saleStoreLevel", planReqRequest.getSaleStoreLevel()) - .queryParam("schPlanReqNo", planReqRequest.getSchPlanReqNo()) + .queryParam("schPlanReqNo", encodedSchPlanReqNo) .queryParam("schTitle", encodedSchTitle) .queryParam("schAddress", encodedSchAddress) .queryParam("schSaleStoreName", encodedSchSaleStoreName) diff --git a/src/main/java/com/interplug/qcast/biz/object/dto/ObjectResponse.java b/src/main/java/com/interplug/qcast/biz/object/dto/ObjectResponse.java index 45069931..072cd47c 100644 --- a/src/main/java/com/interplug/qcast/biz/object/dto/ObjectResponse.java +++ b/src/main/java/com/interplug/qcast/biz/object/dto/ObjectResponse.java @@ -43,6 +43,9 @@ public class ObjectResponse { @Schema(description = "도도부현코드") private String prefId; + @Schema(description = "도도부현명") + private String prefName; + @Schema(description = "주소") private String address; diff --git a/src/main/java/com/interplug/qcast/biz/object/dto/SaleStoreResponse.java b/src/main/java/com/interplug/qcast/biz/object/dto/SaleStoreResponse.java index 72fb9df5..8884ecd8 100644 --- a/src/main/java/com/interplug/qcast/biz/object/dto/SaleStoreResponse.java +++ b/src/main/java/com/interplug/qcast/biz/object/dto/SaleStoreResponse.java @@ -32,4 +32,8 @@ public class SaleStoreResponse { @Schema(description = "영업사원 메일주소") private String businessChargerMail; + + @Schema(description = "정렬") + private String priority; + } diff --git a/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteController.java b/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteController.java index f9248c5b..860a5ff4 100644 --- a/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteController.java +++ b/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteController.java @@ -1,13 +1,20 @@ package com.interplug.qcast.biz.storeFavorite; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteRequest; +import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteResponse; import com.interplug.qcast.biz.user.dto.UserResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.*; @Slf4j @RestController @@ -15,20 +22,30 @@ import org.springframework.web.bind.annotation.*; @RequiredArgsConstructor @Tag(name = "StoreFavorite", description = "Store Favorite 관련 API") public class StoreFavoriteController { - private final StoreFavoriteService storeFavService; + private final StoreFavoriteService storeFavService; - @Operation(description = "Store Favorite 정보를 등록/수정 한다.(동기화)") - @PutMapping("/store-favorite-save") - @ResponseStatus(HttpStatus.OK) - public UserResponse setStoreFavoriteSave(@RequestBody StoreFavoriteRequest req) throws Exception { - UserResponse userResponse = new UserResponse(); + @Operation(description = "Store Favorite 정보를 등록/수정 한다.(동기화)") + @PutMapping("/store-favorite-save") + @ResponseStatus(HttpStatus.OK) + public UserResponse setStoreFavoriteSave(@RequestBody StoreFavoriteRequest req) throws Exception { + UserResponse userResponse = new UserResponse(); - int resultCnt = storeFavService.setStoreFavoriteSave(req); + int resultCnt = storeFavService.setStoreFavoriteSave(req); - if (resultCnt > 0) userResponse.setCode("200"); - else userResponse.setCode("500"); + if (resultCnt > 0) + userResponse.setCode("200"); + else + userResponse.setCode("500"); - return userResponse; - } + return userResponse; + } -} \ No newline at end of file + @Operation(description = "User Store Favorite 목록을 조회한다.") + @GetMapping("/list") + @ResponseStatus(HttpStatus.OK) + public StoreFavoriteResponse getStoreFavoriteList(@ModelAttribute StoreFavoriteRequest req) + throws Exception { + return storeFavService.getStoreFavoriteList(req); + } + +} diff --git a/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteService.java b/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteService.java index ff7121a0..800e30fe 100644 --- a/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteService.java +++ b/src/main/java/com/interplug/qcast/biz/storeFavorite/StoreFavoriteService.java @@ -1,17 +1,64 @@ package com.interplug.qcast.biz.storeFavorite; -import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteRequest; -import lombok.RequiredArgsConstructor; +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; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteRequest; +import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteResponse; +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 lombok.RequiredArgsConstructor; @Service @RequiredArgsConstructor public class StoreFavoriteService { - private final StoreFavoriteMapper storeFavoriteMapper; + private final StoreFavoriteMapper storeFavoriteMapper; - public int setStoreFavoriteSave(StoreFavoriteRequest req) throws Exception { - return storeFavoriteMapper.setStoreFavoriteSave(req); + private final InterfaceQsp interfaceQsp; + + @Autowired + Messages message; + + @Value("${qsp.url}") + private String QSP_API_URL; + + public int setStoreFavoriteSave(StoreFavoriteRequest req) throws Exception { + return storeFavoriteMapper.setStoreFavoriteSave(req); + } + + public StoreFavoriteResponse getStoreFavoriteList(StoreFavoriteRequest req) throws Exception { + + StoreFavoriteResponse response = null; + + /* [0]. Validation Check */ + if ("".equals(req.getUserId())) { + // [msg] {0} is required input value. + throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, + message.getMessage("common.message.required.data", "User Id")); } + /* [1]. QSP API (url + param) Setting */ + String url = QSP_API_URL + "/api/user/storeFavoriteInfoList"; + String apiUrl = UriComponentsBuilder.fromHttpUrl(url).queryParam("userId", req.getUserId()) + .build().toUriString(); + /* [2]. QSP API CALL -> Response */ + String strResponse = interfaceQsp.callApi(HttpMethod.GET, apiUrl, null); + + if (!"".equals(strResponse)) { + ObjectMapper om = + new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + response = om.readValue(strResponse, StoreFavoriteResponse.class); + } else { + // [msg] No data + throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data")); + } + return response; + } } diff --git a/src/main/java/com/interplug/qcast/biz/storeFavorite/dto/StoreFavoriteResponse.java b/src/main/java/com/interplug/qcast/biz/storeFavorite/dto/StoreFavoriteResponse.java new file mode 100644 index 00000000..16a0d205 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/storeFavorite/dto/StoreFavoriteResponse.java @@ -0,0 +1,13 @@ +package com.interplug.qcast.biz.storeFavorite.dto; + +import lombok.Data; + +@Data +public class StoreFavoriteResponse { + /** API response result */ + private Object result; + /** API response data */ + private Object data; +} + + diff --git a/src/main/java/com/interplug/qcast/util/ZipFileManager.java b/src/main/java/com/interplug/qcast/util/ZipFileManager.java index 785b86c8..532f4f4f 100644 --- a/src/main/java/com/interplug/qcast/util/ZipFileManager.java +++ b/src/main/java/com/interplug/qcast/util/ZipFileManager.java @@ -1,37 +1,37 @@ package com.interplug.qcast.util; +import com.interplug.qcast.config.message.Messages; +import jakarta.servlet.http.HttpServletResponse; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import com.interplug.qcast.config.message.Messages; -import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Slf4j @Component @RequiredArgsConstructor public class ZipFileManager { - @Autowired - Messages message; + @Autowired Messages message; /** * zip file을 생성하여 ZipOutputStream를 반환하는 method * * @param response HttpServletResponse * @param strCreateFileName 생성할 file 이름 - * @param listFilePath 파일 정보 목록 + * @param listFile 파일 정보 목록 */ - public void createZipFile(HttpServletResponse response, String strCreateFileName, - List> listFile) throws Exception { + public void createZipFile( + HttpServletResponse response, String strCreateFileName, List> listFile) + throws Exception { + // 압축될 파일명이 존재하지 않을 경우 if (strCreateFileName == null || "".equals(strCreateFileName)) throw new IllegalArgumentException( @@ -44,7 +44,27 @@ public class ZipFileManager { // zip 파일명 String strZipName = strCreateFileName + ".zip"; - // response 설정 + // 파일이 실제로 존재하는지 확인하기 위해 카운트 + int cnt = 0; + for (Map mapFile : listFile) { + String strSourceFile = mapFile.get("filename"); + Path path = Path.of(strSourceFile); + if (path.toFile().exists()) { + cnt++; + } + } + + log.debug("cnt :: " + cnt); + + // 파일이 없을 경우 상태 코드와 메시지 설정 후 종료 + if (cnt == 0) { + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + response.getWriter().write("No files available for download."); + response.flushBuffer(); + return; // 메서드 종료 + } + + // 파일이 있을 경우에만 ZIP 파일 생성 response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename=" + strZipName + ";"); response.setStatus(HttpServletResponse.SC_OK); @@ -55,43 +75,32 @@ public class ZipFileManager { String strSourceFile = mapFile.get("filename"); Path path = Path.of(strSourceFile); - try (FileInputStream fis = new FileInputStream(path.toFile())) { - // 압축될 파일명을 ZipEntry에 담아준다 - ZipEntry zipEntry = new ZipEntry(strDirectory + "\\" + path.getFileName().toString()); + if (!path.toFile().exists()) { + log.debug("파일 변환 작업중, [ " + strSourceFile + " ] 파일을 찾을 수 없습니다."); + continue; // 파일이 없으면 스킵 + } - // 압축될 파일명을 ZipOutputStream 에 담아준다 + try (FileInputStream fis = new FileInputStream(path.toFile())) { + ZipEntry zipEntry = new ZipEntry(strDirectory + "\\" + path.getFileName().toString()); zos.putNextEntry(zipEntry); + byte[] buffer = new byte[1024]; int length; - while ((length = fis.read(buffer)) >= 0) { zos.write(buffer, 0, length); } - } catch (FileNotFoundException e) { - // response.setStatus(HttpServletResponse.SC_NOT_FOUND); - // throw new IllegalArgumentException("파일 변환 작업중, [ " + strSourceFile + " ] 파일을 찾을 수 - // 없습니다."); - log.debug("파일 변환 작업중, [ " + strSourceFile + " ] 파일을 찾을 수 없습니다."); } catch (IOException e) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); throw new IllegalArgumentException( "파일 변환 작업중, [ " + strSourceFile + " ] 파일을 다운로드 할 수 없습니다."); } finally { - // ZipOutputStream 에 담아둔 압축될 파일명을 flush 시켜준다 - zos.flush(); - // ZipOutputStream 에 담아둔 압축될 파일명을 close 시켜준다 zos.closeEntry(); } } } catch (Exception e) { throw e; - } finally { - try { - // response 에 담아둔 파일을 flush 시켜준다 - response.flushBuffer(); - } catch (IOException e) { - throw e; - } } + + response.flushBuffer(); } } diff --git a/src/main/resources/mappers/displayItem/displayItemMapper.xml b/src/main/resources/mappers/displayItem/displayItemMapper.xml index b84cba3a..32f94fa8 100644 --- a/src/main/resources/mappers/displayItem/displayItemMapper.xml +++ b/src/main/resources/mappers/displayItem/displayItemMapper.xml @@ -43,4 +43,63 @@ , #{lastEditDatetime} ); + + + + + diff --git a/src/main/resources/mappers/estimate/estimateMapper.xml b/src/main/resources/mappers/estimate/estimateMapper.xml new file mode 100644 index 00000000..091c3d9f --- /dev/null +++ b/src/main/resources/mappers/estimate/estimateMapper.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + /* sqlid : com.interplug.qcast.biz.estimate.updateEstimate */ + UPDATE T_PLAN + SET + ESTIMATE_TYPE = #{estimateType} + + + , CONSTRUCT_SPECIFICATION = #{constructSpecification} + , SETUP_HEIGHT = #{setupHeight} + , WEATHER_POINT = #{weatherPoint} + , SLOPE = #{slope} + , ROOF_MATERIAL_ID = #{roofMaterialId} + , SUPPORT_METHOD_ID = #{supportMethodId} + , DRAWING_ESTIMATE_CREATE_DATE = GETDATE() + , CHARGER = #{charger} + , ESTIMATE_VALIDITY_TERM = '発行日より1ヶ月' + , SNOWFALL = #{snowfall} + , STANDARD_WIND_SPEED_ID = #{standardWindSpeedId} + , SUPPORT_MEAKER = #{supportMeaker} + , NORTH_ARRANGEMENT = #{northArrangement} + , ROOF_MATERIAL_ID_MULTI = #{roofMaterialIdMulti} + , SUPPORT_METHOD_ID_MULTI = #{supportMethodIdMulti} + , SUPPORT_MEAKER_MULTI = #{supportMeaker} + , ESTIMATE_DATE = CONVERT(NVARCHAR(10), GETDATE(), 121) + , FILE_FLG = '0' + , ESTIMATE_OPTION = NULL + , PKG_ASP = NULL + , PRICE_CD = #{priceCd} + + + , CHARGER = #{charger} + , ESTIMATE_DATE = #{estimateDate} + , FILE_FLG = #{fileFlg} + , ESTIMATE_OPTION = #{estimateOption} + , REMARKS = #{remarks} + , PKG_ASP = #{pkgAsp} + , PRICE_CD = #{priceCd} + + + , CAPACITY = #{capacity} + , MODULE_MODEL = #{moduleModel} + , PC_TYPE_NO = #{pcTypeNo} + , LAST_EDIT_DATETIME = GETDATE() + , LAST_EDIT_USER = #{userId} + WHERE OBJECT_NO = #{objectNo} + AND PLAN_NO = #{planNo} + + + + /* sqlid : com.interplug.qcast.biz.estimate.insertEstimateItem*/ + INSERT INTO T_PART_ESTIMATE + ( + OBJECT_NO + , PLAN_NO + , DISP_ORDER + , ITEM_ID + , ITEM_NO + , ITEM_NAME + , UNIT + , SPECIFICATION + , AMOUNT + + , AMOUNT_CHANGE + + , PART_ADD + , LAST_EDIT_DATETIME + , LAST_EDIT_USER + , SALE_PRICE + , PKG_MATERIAL_FLG + , ITEM_CHANGE_FLG + ) VALUES ( + #{objectNo} + , #{planNo} + , #{dispOrder} + , #{itemId} + , #{itemNo} + , #{itemName} + , #{unit} + , #{specification} + , #{amount} + + , #{amountChange} + + , #{partAdd} + , GETDATE() + , #{userId} + , #{salePrice} + , #{pkgMaterialFlg} + , #{itemChangeFlg} + ) + + + + /* sqlid : com.interplug.qcast.biz.estimate.deleteEstimateItemList */ + DELETE FROM T_PART_ESTIMATE + WHERE OBJECT_NO = #{objectNo} + AND PLAN_NO = #{planNo} + + + \ No newline at end of file diff --git a/src/main/resources/mappers/object/objectMapper.xml b/src/main/resources/mappers/object/objectMapper.xml index ce60e0c0..e37d8c45 100644 --- a/src/main/resources/mappers/object/objectMapper.xml +++ b/src/main/resources/mappers/object/objectMapper.xml @@ -261,9 +261,15 @@ , (SELECT NAME FROM M_USER WHERE USER_ID = O.LAST_EDIT_USER) AS LAST_EDIT_USER_NAME , S.FIRST_AGENT_ID , S.SALE_STORE_LEVEL + , ISNULL(P.PREF_NAME, '') AS PREF_NAME + , ISNULL(PA.AREA_NAME, '') AS AREA_NAME FROM T_OBJECT O WITH (NOLOCK) INNER JOIN M_SALES_STORE S WITH(NOLOCK) ON O.SALE_STORE_ID = S.SALE_STORE_ID + LEFT OUTER JOIN M_PREFECTURE P + ON O.PREF_ID = P.PREF_ID + LEFT OUTER JOIN M_PREFECTURE_AREA PA + ON O.AREA_ID = PA.AREA_ID WHERE O.OBJECT_NO = #{objectNo} AND (O.DEL_FLG = '0' OR (O.TEMP_FLG = '1' AND O.TEMP_DEL_FLG = '0'))