24282 %!s(int64=2) %!d(string=hai) anos
pai
achega
d463f8508e

+ 1 - 0
bladex-saas-project/saas-business-tradeerp/src/main/java/com/fjhx/funds/v2/service/impl/RequestFundsV2FlowServiceImpl.java

@@ -427,4 +427,5 @@ public class RequestFundsV2FlowServiceImpl implements IRequestFundsV2FlowService
         // 发送消息通知
         iMessageNoticeService.send(entity.getProcessInstanceId(), collect, content, MessageNoticeEnum.MESSAGE_NOTICE_TYPE_18.getKey());
     }
+
 }

+ 30 - 6
bladex-saas-project/saas-business-tradeerp/src/main/java/com/fjhx/purchase/controller/PurchaseDocumentaryController.java

@@ -1,6 +1,8 @@
 package com.fjhx.purchase.controller;
 
+import cn.hutool.core.io.IoUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fjhx.purchase.dto.PdfPreviewDto;
 import com.fjhx.purchase.entity.PurchaseContractProduct;
 import com.fjhx.purchase.entity.PurchaseContractVO;
 import com.fjhx.purchase.enums.ManufactureStatusEnum;
@@ -13,19 +15,18 @@ import com.fjhx.track.entity.Track;
 import com.fjhx.track.service.ITrackService;
 import com.fjhx.trackpacking.entity.TrackPackingInstructions;
 import com.fjhx.trackpacking.service.ITrackPackingInstructionsService;
+import lombok.extern.slf4j.Slf4j;
 import org.springblade.common.constant.ApiConstant;
 import org.springblade.common.utils.ListPageMap;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.system.attachment.entity.Attachment;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -36,6 +37,7 @@ import java.util.Map;
  * @Author:caozj
  * @DATE:2022/2/21 17:58
  */
+@Slf4j
 @RestController
 @RequestMapping(ApiConstant.Project.SAAS_BUSINESS_TRADEERP_REQUEST_PREFIX + "/purchase/documentary")
 public class PurchaseDocumentaryController {
@@ -58,6 +60,9 @@ public class PurchaseDocumentaryController {
     @Autowired
     private IShipmentDetailedService iShipmentDetailedService;
 
+    @Autowired
+    private HttpServletResponse response;
+
     /**
      * 列表
      *
@@ -150,4 +155,23 @@ public class PurchaseDocumentaryController {
         return R.details(attachment);
     }
 
+    /**
+     * 生成pdf
+     */
+    @GetMapping("/pdfPreview")
+    public void pdfPreview(@RequestBody PdfPreviewDto pdfPreviewDto) {
+        ServletOutputStream outputStream = null;
+        try {
+            response.setContentType("application/pdf");
+            response.setHeader("Content-Disposition", "inline; filename=预览文件.pdf");
+            outputStream = response.getOutputStream();
+            service.pdfPreview(pdfPreviewDto, outputStream);
+        } catch (Exception e) {
+            log.error("预览pdf失败", e);
+            throw new ServiceException("预览pdf失败");
+        } finally {
+            IoUtil.close(outputStream);
+        }
+    }
+
 }

+ 153 - 0
bladex-saas-project/saas-business-tradeerp/src/main/java/com/fjhx/purchase/dto/PdfPreviewDto.java

@@ -0,0 +1,153 @@
+package com.fjhx.purchase.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fjhx.company.entity.Company;
+import com.fjhx.supply.entity.Supply;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class PdfPreviewDto {
+
+    /**
+     * 总价
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 总数量
+     */
+    private Integer totalQuantity;
+
+    /**
+     * 企业id
+     */
+    private String companyId;
+
+    /**
+     * 供应商od
+     */
+    private String supplyId;
+
+    /**
+     * 合同信息
+     */
+    private PurchaseContractDto purchaseContract;
+
+    /**
+     * 产品集合
+     */
+    private List<ProductDto> products;
+
+    /**
+     * 出货明细
+     */
+    private List<ShipmentDto> shipments;
+
+    /**
+     * 收费项目
+     */
+    List<ProjectDto> projects;
+
+
+    // ====================================
+
+    /**
+     * 华为云路径
+     */
+    private String huaWeiUrl;
+
+    /**
+     * 审核通过时间
+     */
+    private String approvedDate;
+
+    /**
+     * 企业信息
+     */
+    private Company company;
+
+    /**
+     * 企业详细地址
+     */
+    private String companyAddress1;
+    private String companyAddress2;
+
+    /**
+     * 供应商信息
+     */
+    private Supply supply;
+
+    /**
+     * 供应商详细地址
+     */
+    private String supplyAddress1;
+    private String supplyAddress2;
+
+    /**
+     * 大写总价
+     */
+    private String unitTotalAmount;
+
+    /**
+     * 交货日期
+     */
+    private String deliveryTime;
+
+    @Data
+    public static class PurchaseContractDto {
+        private String code;
+        private String supplyName;
+        private String supplyContactName;
+        private String receivingProvinceName;
+        private String receivingCityName;
+        private String receivingAddress;
+        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private Date deliveryTime;
+        private String warrantyPeriod;
+        private String remark;
+        private String supplyContactTel;
+        private Integer receivingAddrType;
+        private Integer payType;
+        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private Date createTime;
+    }
+
+    @Data
+    public static class ProductDto {
+        private String id;
+        private String parentId;
+        private String productName;
+        private String productModelChinese;
+        private String productLong;
+        private String productWide;
+        private String productHigh;
+        private String quantity;
+        private String productUnit;
+        private String price;
+        private BigDecimal sumPrice;
+        private String remark;
+        private String productMainImg;
+        private String productLogo;
+    }
+
+    @Data
+    public static class ProjectDto {
+        private String projectName;
+        private String projectPrice;
+    }
+
+    @Data
+    public static class ShipmentDto {
+        private String shipmentTime;
+        private String productName;
+        private String shipmentQuantity;
+    }
+
+}

+ 6 - 0
bladex-saas-project/saas-business-tradeerp/src/main/java/com/fjhx/purchase/service/IPurchaseContractPdfService.java

@@ -1,7 +1,10 @@
 package com.fjhx.purchase.service;
 
+import com.fjhx.purchase.dto.PdfPreviewDto;
 import org.springblade.system.attachment.entity.Attachment;
 
+import javax.servlet.ServletOutputStream;
+
 /**
  * 生成外销合同pdf
  */
@@ -14,4 +17,7 @@ public interface IPurchaseContractPdfService {
      */
     Attachment generate(String id);
 
+
+    void pdfPreview(PdfPreviewDto pdfPreviewDto, ServletOutputStream outputStream) throws Exception;
+
 }

+ 116 - 12
bladex-saas-project/saas-business-tradeerp/src/main/java/com/fjhx/purchase/service/impl/PurchaseContractPdfServiceImpl.java

@@ -1,10 +1,13 @@
 package com.fjhx.purchase.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.fjhx.common.attachment.IAttachmentApi;
 import com.fjhx.common.service.ICommonService;
 import com.fjhx.company.entity.Company;
 import com.fjhx.company.service.ICompanyService;
+import com.fjhx.purchase.dto.PdfPreviewDto;
 import com.fjhx.purchase.entity.PurchaseContract;
 import com.fjhx.purchase.entity.PurchaseContractProduct;
 import com.fjhx.purchase.entity.PurchaseContractProject;
@@ -16,6 +19,7 @@ import com.fjhx.shipmentdetailed.entity.ShipmentDetailed;
 import com.fjhx.shipmentdetailed.service.IShipmentDetailedService;
 import com.fjhx.supply.entity.Supply;
 import com.fjhx.supply.service.ISupplyService;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -38,6 +42,7 @@ import org.springblade.system.attachment.entity.Attachment;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.ServletOutputStream;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.*;
@@ -47,19 +52,16 @@ import java.util.stream.Collectors;
  * 生成外销合同pdf
  */
 @Service
+@Slf4j
 public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfService {
 
     //富文本每行多少个文字
     private static final int text_row_count = 45;
     //富文本每行多少个文字追加的符号
     private static final String text_row_symbol = "<br/>";
-
     //模板文件名称
     private final String template_name = "purchase_contract";
 
-    //临时保存文件夹
-    private final String temp_folder = "/temp/purchase/contract/pdf";
-
     @Autowired
     private ICommonService commonService;
 
@@ -95,7 +97,7 @@ public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfServi
     @Override
     public Attachment generate(String id) {
         try {
-            //获取参数
+            // 获取参数
             Map variablesMap = getVariablesMap(id);
             //采购id
             String purchaseId = (String) variablesMap.get("purchaseId");
@@ -124,11 +126,11 @@ public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfServi
             Attachment attachment = attachmentJson.toJavaObject(Attachment.class);
             //业务id=报价单id
             attachment.setBusiId(purchaseId);
-            //附件类型=pdf
+            // 附件类型=pdf
             attachment.setBusiType(AttachmentConstant.BusiType.PDF);
-            //删除pdf附件
+            // 删除pdf附件
             attachmentApi.deleteByBusiIdAndType(purchaseId, AttachmentConstant.BusiType.PDF);
-            //保存附件
+            // 保存附件
             attachmentApi.batchInsert(Collections.singletonList(attachment));
             return attachment;
         } catch (Exception e) {
@@ -137,13 +139,34 @@ public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfServi
     }
 
     /**
+     * 地址长度过长,默认截取的长度
+     */
+    private static final int defaultLength = 22;
+
+    @Override
+    public void pdfPreview(PdfPreviewDto pdfPreviewDto, ServletOutputStream outputStream) throws Exception {
+
+        // 数据处理
+        handlePdfPreviewData(pdfPreviewDto);
+
+        // 生成pdf
+        String temp = template_name + "_" + AuthUtil.getTenantId();
+        // 判断租户定制模板是否存在,如果不存在使用默认模板
+        if (!ThymeleafPdfUtil.existTemplate(temp)) {
+            temp = template_name;
+        }
+
+        ThymeleafPdfUtil.generate(temp, BeanUtil.beanToMap(pdfPreviewDto), outputStream);
+    }
+
+    /**
      * 获取参数
      *
      * @param id
      * @return
      */
     private Map getVariablesMap(String id) {
-        //采购合同信息
+        // 采购合同信息
         PurchaseContract purchaseContract = purchaseContractService.getById(id);
         if (purchaseContract == null) {
             throw new ServiceException("生成采购合同PDF文件失败:采购合同不存在");
@@ -159,7 +182,9 @@ public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfServi
             // 标签过滤
             Document document = Jsoup.parse(remark);
             remark = document.text();
+
             String[] remarkArr = remark.split(purchaseContract.getCode());
+
             StringBuilder sb = new StringBuilder();
             for (String s : remarkArr) {
                 if (s.length() > text_row_count + 7) {
@@ -168,7 +193,6 @@ public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfServi
                 sb.append(s).append(text_row_symbol);
             }
             remark = sb.toString();
-//            remark = remark.replaceAll("font-size:", "");
             purchaseContract.setRemark(remark);
         }
 
@@ -282,8 +306,6 @@ public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfServi
             payTypeName = PayTypeEnum.getNameByKey(Integer.valueOf(purchaseContract.getPayType()));
         }
 
-        //地址长度过长,默认截取的长度
-        Integer defaultLength = 22;
 
         //公司详细地址
         String companyAddress = company.getProvinceChinese() + company.getCityChinese() + company.getAddressChinese();
@@ -328,4 +350,86 @@ public class PurchaseContractPdfServiceImpl implements IPurchaseContractPdfServi
         return variablesMap;
     }
 
+    private void handlePdfPreviewData(PdfPreviewDto pdfPreviewDto) {
+        pdfPreviewDto.setHuaWeiUrl(commonService.getHuaWeiUrl());
+        pdfPreviewDto.setApprovedDate(DateUtils.parseDateToStr(DateUtils.DD_MMM_YYYY, new Date(), Locale.ENGLISH));
+        pdfPreviewDto.setUnitTotalAmount(MoneyUtil.number2CNMontrayUnit(ObjectUtil.defaultIfNull(pdfPreviewDto.getTotalAmount(), BigDecimal.ZERO)));
+
+        // 赋值交货日期
+        if (pdfPreviewDto.getPurchaseContract() != null && pdfPreviewDto.getPurchaseContract().getDeliveryTime() != null) {
+            pdfPreviewDto.setDeliveryTime(cn.hutool.core.date.DateUtil.formatDateTime(pdfPreviewDto.getPurchaseContract().getDeliveryTime()));
+        }
+
+        // 企业信息
+        Company company = ObjectUtil.defaultIfNull(companyService.getById(ObjectUtil.defaultIfNull(pdfPreviewDto.getCompanyId(), -99999)), new Company());
+        pdfPreviewDto.setCompany(company);
+        // 企业详细地址
+        String companyAddress = company.getProvinceChinese() + company.getCityChinese() + company.getAddressChinese();
+        if (StringUtils.isNotBlank(companyAddress) && companyAddress.length() > defaultLength) {
+            pdfPreviewDto.setCompanyAddress1(StringUtils.substring(companyAddress, 0, defaultLength));
+            pdfPreviewDto.setCompanyAddress2(StringUtils.substring(companyAddress, defaultLength));
+        } else {
+            pdfPreviewDto.setCompanyAddress1("");
+            pdfPreviewDto.setCompanyAddress2("");
+        }
+
+        // 供应商信息
+        Supply supply = ObjectUtil.defaultIfNull(supplyService.getById(pdfPreviewDto.getSupplyId()), new Supply());
+        pdfPreviewDto.setSupply(supply);
+        // 供应商详细地址
+        String supplyAddress = supply.getProvinceName() + supply.getCityName() + supply.getAddress();
+        if (StringUtils.isNotBlank(supplyAddress) && supplyAddress.length() > defaultLength) {
+            pdfPreviewDto.setSupplyAddress1(StringUtils.substring(supplyAddress, 0, defaultLength));
+            pdfPreviewDto.setSupplyAddress2(StringUtils.substring(supplyAddress, defaultLength));
+        } else {
+            pdfPreviewDto.setSupplyAddress1("");
+            pdfPreviewDto.setSupplyAddress2("");
+        }
+
+        List<PdfPreviewDto.ProductDto> products = pdfPreviewDto.getProducts();
+        if (CollectionUtils.isNotEmpty(products)) {
+            for (PdfPreviewDto.ProductDto product : products) {
+                if (StringUtils.isNotBlank(product.getRemark())) {
+                    // 富文本内容每个n位追加符号
+                    String remark = CommonUtil.nodeTextAppendBR(product.getRemark(), text_row_symbol, text_row_count)
+                            .replaceAll("&nbsp;", "")
+                            .replaceAll("style=", "aaa=");
+                    product.setRemark(remark);
+                }
+            }
+        }
+        
+        PdfPreviewDto.PurchaseContractDto purchaseContract = pdfPreviewDto.getPurchaseContract();
+        if (purchaseContract == null) {
+            purchaseContract = new PdfPreviewDto.PurchaseContractDto();
+            pdfPreviewDto.setPurchaseContract(purchaseContract);
+        }
+        if (StringUtils.isNotBlank(purchaseContract.getRemark())) {
+            // 内容特殊符号转义
+            String remark = purchaseContract.getRemark();
+            remark = remark.replaceAll("&lt;", "<")
+                    .replaceAll("&gt;", ">")
+                    .replaceAll("&nbsp;", "")
+                    .replaceAll("&quot;", "'");
+            // 富文本内容每隔n位追加符号
+            remark = CommonUtil.nodeTextAppendBR(remark, text_row_symbol, text_row_count);
+            remark = remark.replaceAll("</", purchaseContract.getCode() + "</");
+            // 标签过滤
+            Document document = Jsoup.parse(remark);
+            remark = document.text();
+
+            String[] remarkArr = remark.split(purchaseContract.getCode());
+
+            StringBuilder sb = new StringBuilder();
+            for (String s : remarkArr) {
+                if (s.length() > text_row_count + 7) {
+                    s = CommonUtil.displayWithComma(s, text_row_symbol, text_row_count + 7);
+                }
+                sb.append(s).append(text_row_symbol);
+            }
+            remark = sb.toString();
+            purchaseContract.setRemark(remark);
+        }
+    }
+
 }

+ 8 - 10
bladex/blade-common/src/main/java/org/springblade/common/utils/MoneyUtil.java

@@ -1,6 +1,9 @@
 package org.springblade.common.utils;
 
+import cn.hutool.core.util.ObjectUtil;
+
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.text.DecimalFormat;
 
 /**
@@ -43,17 +46,17 @@ public class MoneyUtil {
      * @return 对应的汉语大写
      */
     public static String number2CNMontrayUnit(BigDecimal numberOfMoney) {
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         // -1, 0, or 1 as the value of this BigDecimal is negative, zero, or
         // positive.
-        int signum = numberOfMoney.signum();
+        int signum = ObjectUtil.defaultIfNull(numberOfMoney.signum(), 0);
         // 零元整的情况
         if (signum == 0) {
             return CN_ZEOR_FULL;
         }
         // 这里会进行金额的四舍五入
         long number = numberOfMoney.movePointRight(MONEY_PRECISION)
-                .setScale(0, 4).abs().longValue();
+                .setScale(0, RoundingMode.HALF_UP).abs().longValue();
         // 得到小数点后两位值
         long scale = number % 100;
         int numUnit = 0;
@@ -71,10 +74,7 @@ public class MoneyUtil {
             getZero = true;
         }
         int zeroSize = 0;
-        while (true) {
-            if (number <= 0) {
-                break;
-            }
+        while (number > 0) {
             // 每次获取到最后一个数
             numUnit = (int) (number % 10);
             if (numUnit > 0) {
@@ -94,9 +94,7 @@ public class MoneyUtil {
                     sb.insert(0, CN_UPPER_NUMBER[numUnit]);
                 }
                 if (numIndex == 2) {
-                    if (number > 0) {
-                        sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
-                    }
+                    sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                 } else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) {
                     sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                 }

+ 22 - 7
bladex/blade-common/src/main/java/org/springblade/common/utils/pdf/ThymeleafPdfUtil.java

@@ -22,6 +22,7 @@ import org.xhtmlrenderer.pdf.ITextRenderer;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -80,6 +81,21 @@ public class ThymeleafPdfUtil {
      * @throws Exception
      */
     public static byte[] generateByte(String templateName, Map variables) throws Exception {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        generate(templateName, variables, byteArrayOutputStream);
+        byte[] bytes = byteArrayOutputStream.toByteArray();
+        IoUtil.close(byteArrayOutputStream);
+        return bytes;
+    }
+
+    /**
+     * 根据模板生成一个PDF
+     *
+     * @param templateName 模板名称
+     * @param variables    页面参数
+     * @throws Exception
+     */
+    public static void generate(String templateName, Map variables, OutputStream outputStream) throws Exception {
         // 为空初始化
         variables = Optional.ofNullable(variables).orElse(new HashMap());
 
@@ -89,7 +105,10 @@ public class ThymeleafPdfUtil {
         final TemplateEngine templateEngine = new ThymeleafPdfUtil().getTemplateEngine();
 
         // 替换转义
-        String htmlContent = templateEngine.process(templateName, ctx).replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "'");
+        String htmlContent = templateEngine.process(templateName, ctx)
+                .replaceAll("&lt;", "<")
+                .replaceAll("&gt;", ">")
+                .replaceAll("&quot;", "'");
 
         ITextRenderer renderer = new ITextRenderer();
         ITextFontResolver fontResolver = renderer.getFontResolver();
@@ -109,14 +128,10 @@ public class ThymeleafPdfUtil {
         renderer.getSharedContext().setReplacedElementFactory(new Base64ImgReplacedElementFactory());
         renderer.setDocumentFromString(htmlContent);
         renderer.layout();
-
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        renderer.createPDF(byteArrayOutputStream);
-        byte[] bytes = byteArrayOutputStream.toByteArray();
-        IoUtil.close(byteArrayOutputStream);
-        return bytes;
+        renderer.createPDF(outputStream);
     }
 
+
     /**
      * 获取字体路径
      *