diff --git a/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java b/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java index b616d094..897b999f 100644 --- a/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java +++ b/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java @@ -20,6 +20,12 @@ import com.interplug.qcast.biz.canvaspopupstatus.dto.CanvasPopupStatus; import com.interplug.qcast.biz.pwrGnrSimulation.dto.PwrGnrSimRoofResponse; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.jsoup.nodes.Document; @@ -1470,6 +1476,7 @@ public class EstimateService { this.selectTotalPriceInfo(estimateResponse, estimateItemList, estimateRequest.getSchUnitPriceFlg()); + boolean isPdfDownload = "PDF".equals(estimateRequest.getSchDownload()); int j = 1; for (ItemResponse itemResponse : estimateItemList) { itemResponse.setNo(String.valueOf(j++)); @@ -1499,13 +1506,15 @@ public class EstimateService { } } - // 문자열 통화로 변환 처리 - itemResponse.setSalePrice( - String.format("%1$,.0f", Double.parseDouble(itemResponse.getSalePrice()))); - itemResponse - .setAmount(String.format("%1$,.0f", Double.parseDouble(itemResponse.getAmount()))); - itemResponse.setSaleTotPrice( - String.format("%1$,.0f", Double.parseDouble(itemResponse.getSaleTotPrice()))); + // 문자열 통화로 변환 처리 (PDF 전용) + if (isPdfDownload) { + itemResponse.setSalePrice( + String.format("%1$,.0f", Double.parseDouble(itemResponse.getSalePrice()))); + itemResponse.setAmount( + String.format("%1$,.0f", Double.parseDouble(itemResponse.getAmount()))); + itemResponse.setSaleTotPrice( + String.format("%1$,.0f", Double.parseDouble(itemResponse.getSaleTotPrice()))); + } if ("YJSS".equals(estimateResponse.getEstimateType()) && (!StringUtils.isEmpty(itemResponse.getPaDispOrder()) @@ -1533,20 +1542,22 @@ public class EstimateService { estimateResponse.setPkgYn("YJSS".equals(estimateResponse.getEstimateType()) ? "Y" : "N"); estimateResponse .setPkgNo("YJSS".equals(estimateResponse.getEstimateType()) ? String.valueOf(j++) : ""); - if ("YJSS".equals(estimateResponse.getEstimateType())) { - estimateResponse - .setPkgAsp(String.format("%1$,.0f", Double.parseDouble(estimateResponse.getPkgAsp()))); + if (isPdfDownload) { + if ("YJSS".equals(estimateResponse.getEstimateType())) { + estimateResponse.setPkgAsp( + String.format("%1$,.0f", Double.parseDouble(estimateResponse.getPkgAsp()))); + } + estimateResponse.setTotVol( + String.format("%1$,.0f", Double.parseDouble(estimateResponse.getTotVol()))); + estimateResponse.setPkgTotPrice( + String.format("%1$,.0f", Double.parseDouble(estimateResponse.getPkgTotPrice()))); + estimateResponse.setSupplyPrice( + String.format("%1$,.0f", Double.parseDouble(estimateResponse.getSupplyPrice()))); + estimateResponse.setVatPrice( + String.format("%1$,.0f", Double.parseDouble(estimateResponse.getVatPrice()))); + estimateResponse.setTotPrice( + String.format("%1$,.0f", Double.parseDouble(estimateResponse.getTotPrice()))); } - estimateResponse - .setTotVol(String.format("%1$,.0f", Double.parseDouble(estimateResponse.getTotVol()))); - estimateResponse.setPkgTotPrice( - String.format("%1$,.0f", Double.parseDouble(estimateResponse.getPkgTotPrice()))); - estimateResponse.setSupplyPrice( - String.format("%1$,.0f", Double.parseDouble(estimateResponse.getSupplyPrice()))); - estimateResponse.setVatPrice( - String.format("%1$,.0f", Double.parseDouble(estimateResponse.getVatPrice()))); - estimateResponse.setTotPrice( - String.format("%1$,.0f", Double.parseDouble(estimateResponse.getTotPrice()))); // 발전시뮬레이션 계산 PwrGnrSimRequest pwrGnrSimRequest = new PwrGnrSimRequest(); @@ -1592,24 +1603,16 @@ public class EstimateService { String baseDrawingImgName = estimateRequest.getObjectNo() + "_" + estimateRequest.getPlanNo(); URL url = new URL(drawingDirPath + File.separator + baseDrawingImgName + "_1.png"); - URLConnection con = url.openConnection(); - HttpURLConnection exitCode = (HttpURLConnection)con; - if (exitCode.getResponseCode() == 200) { - InputStream imageInputStream = - new URL(drawingDirPath + File.separator + baseDrawingImgName + "_1.png").openStream(); - byte[] drawingImg1 = Util.toByteArray(imageInputStream); + byte[] drawingImg1 = loadDrawingImage(url); + if (drawingImg1 != null) { estimateResponse.setDrawingImg1(drawingImg1); } log.debug("url1 ::: {}", url); String baseDrawingImgName2 = estimateRequest.getObjectNo() + "_" + estimateRequest.getPlanNo(); URL url2 = new URL(drawingDirPath + File.separator + baseDrawingImgName2 + "_2.png"); - URLConnection con2 = url2.openConnection(); - HttpURLConnection exitCode2 = (HttpURLConnection)con2; - if (exitCode2.getResponseCode() == 200) { - InputStream imageInputStream2 = - new URL(drawingDirPath + File.separator + baseDrawingImgName2 + "_2.png").openStream(); - byte[] drawingImg2 = Util.toByteArray(imageInputStream2); + byte[] drawingImg2 = loadDrawingImage(url2); + if (drawingImg2 != null) { estimateResponse.setDrawingImg2(drawingImg2); } log.debug("url2 ::: {}", url2); @@ -1807,9 +1810,18 @@ public class EstimateService { estimateResponse.setPcsList3(pcsList3); excelUtil = new ExcelUtil(); + Map excelData = excelUtil.convertVoToMap(estimateResponse); + List> excelList = excelUtil.convertListToMap(estimateItemList); + coerceExcelDataNumberFields(excelData); + coerceExcelItemNumberFields(excelList); + putExcelItemList(excelData, "itemList", estimateResponse.getItemList()); + putExcelItemList(excelData, "estimateItemList15", estimateResponse.getEstimateItemList15()); + putExcelItemList(excelData, "estimateItemListS15", estimateResponse.getEstimateItemListS15()); + putExcelItemList(excelData, "circuitItemList11", estimateResponse.getCircuitItemList11()); + putExcelRoofList(excelData, "roofModuleList8", estimateResponse.getRoofModuleList8()); + putExcelRoofList(excelData, "pcsList3", estimateResponse.getPcsList3()); byte[] excelBytes = - excelUtil.download(request, response, excelUtil.convertVoToMap(estimateResponse), - excelUtil.convertListToMap(estimateItemList), excelTemplateNam); + excelUtil.download(request, response, excelData, excelList, excelTemplateNam); InputStream in = new ByteArrayInputStream(excelBytes); workbook = WorkbookFactory.create(in); // JXLS POI 엑셀로 재변환 @@ -1856,6 +1868,8 @@ public class EstimateService { safeRemoveSheet(workbook, "特異事項"); } + applyExcelNumberFormat(workbook); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); workbook.write(byteArrayOutputStream); excelBytes = byteArrayOutputStream.toByteArray(); @@ -1964,6 +1978,150 @@ public class EstimateService { estimateResponse.setTotPrice(String.valueOf(totPrice.setScale(0, BigDecimal.ROUND_HALF_UP))); } + private static final Set EXCEL_ITEM_NUMBER_FIELDS = new HashSet<>( + Arrays.asList("amount", "bomAmount", "salePrice", "unitPrice", "saleTotPrice", "grossWt", "pnowW")); + + private static final Set EXCEL_DATA_NUMBER_FIELDS = new HashSet<>( + Arrays.asList("pkgAsp", "totAmount", "totVol", "totVolKw", "pkgTotPrice", + "supplyPrice", "vatPrice", "totPrice")); + + private static final Set EXCEL_ROOF_NUMBER_FIELDS = new HashSet<>( + Arrays.asList("amount", "totSpecification", "specification", "cnvEff", + "amp", "tempLoss", "tempCoeff")); + + private static void coerceExcelItemNumberFields(List> list) { + if (list == null) { + return; + } + for (Map row : list) { + coerceExcelNumberFields(row, EXCEL_ITEM_NUMBER_FIELDS); + } + } + + private static void coerceExcelDataNumberFields(Map map) { + coerceExcelNumberFields(map, EXCEL_DATA_NUMBER_FIELDS); + } + + private static void coerceExcelRoofNumberFields(List> list) { + if (list == null) { + return; + } + for (Map row : list) { + coerceExcelNumberFields(row, EXCEL_ROOF_NUMBER_FIELDS); + } + } + + private static void coerceExcelNumberFields(Map map, Set fields) { + if (map == null || fields == null) { + return; + } + for (String key : fields) { + if (!map.containsKey(key)) { + continue; + } + Object value = map.get(key); + Object parsed = parseExcelNumber(value); + map.put(key, parsed); + } + } + + private static Object parseExcelNumber(Object value) { + if (value == null) { + return null; + } + if (value instanceof Number) { + return value; + } + if (!(value instanceof String)) { + return value; + } + String raw = ((String) value).trim(); + if (raw.isEmpty()) { + return value; + } + String normalized = raw.replace(",", ""); + if (!normalized.matches("[-+]?\\d+(\\.\\d+)?")) { + return value; + } + try { + return new BigDecimal(normalized); + } catch (NumberFormatException e) { + return value; + } + } + + private static void putExcelItemList(Map excelData, String key, + List items) { + if (excelData == null || items == null) { + return; + } + List> list = ExcelUtil.convertListToMap(items); + coerceExcelItemNumberFields(list); + excelData.put(key, list); + } + + private static void putExcelRoofList(Map excelData, String key, + List items) { + if (excelData == null || items == null) { + return; + } + List> list = ExcelUtil.convertListToMap(items); + coerceExcelRoofNumberFields(list); + excelData.put(key, list); + } + + private static void applyExcelNumberFormat(Workbook workbook) { + if (workbook == null) { + return; + } + DataFormat dataFormat = workbook.createDataFormat(); + short numberFormat = dataFormat.getFormat("#,##0.###"); + Map styleCache = new HashMap<>(); + + for (int s = 0; s < workbook.getNumberOfSheets(); s++) { + Sheet sheet = workbook.getSheetAt(s); + if (sheet == null) { + continue; + } + for (Row row : sheet) { + for (Cell cell : row) { + CellType cellType = cell.getCellType(); + CellStyle style = cell.getCellStyle(); + boolean isTextFormat = style != null && "@".equals(style.getDataFormatString()); + + if (cellType == CellType.STRING) { + Object parsed = parseExcelNumber(cell.getStringCellValue()); + if (parsed instanceof Number) { + cell.setCellValue(((Number) parsed).doubleValue()); + cellType = CellType.NUMERIC; + } else { + continue; + } + } + + if (cellType != CellType.NUMERIC) { + continue; + } + + if (!isTextFormat) { + continue; + } + + short styleIdx = style.getIndex(); + CellStyle cached = styleCache.get(styleIdx); + if (cached == null) { + CellStyle newStyle = workbook.createCellStyle(); + newStyle.cloneStyleFrom(style); + newStyle.setDataFormat(numberFormat); + styleCache.put(styleIdx, newStyle); + cached = newStyle; + } + cell.setCellStyle(cached); + } + } + } + } + /** * QSP Q.CAST 견적서 전송 API * @@ -2692,4 +2850,22 @@ public class EstimateService { workbook.removeSheetAt(sheetIndex); } } + + private byte[] loadDrawingImage(URL url) { + try { + URLConnection connection = url.openConnection(); + if (connection instanceof HttpURLConnection) { + HttpURLConnection httpConnection = (HttpURLConnection) connection; + if (httpConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { + return null; + } + } + try (InputStream imageInputStream = connection.getInputStream()) { + return Util.toByteArray(imageInputStream); + } + } catch (Exception e) { + log.warn("Failed to load drawing image. url={}", url, e); + return null; + } + } } diff --git a/src/main/resources/template/excel/excel_download_quotation_detail_template.xlsx b/src/main/resources/template/excel/excel_download_quotation_detail_template.xlsx index ba435c89..44c1ae17 100644 Binary files a/src/main/resources/template/excel/excel_download_quotation_detail_template.xlsx and b/src/main/resources/template/excel/excel_download_quotation_detail_template.xlsx differ