Browse Source

上传结算单的回执单

Yangzw 7 months ago
parent
commit
73d67e56e9
13 changed files with 666 additions and 2 deletions
  1. 19 0
      feifan-module-distri/feifan-module-distri-api/src/main/java/cn/newfeifan/mall/module/distri/enums/PtSettlemntStatusEnum.java
  2. 7 0
      feifan-module-distri/feifan-module-distri-biz/pom.xml
  3. 10 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/PtSettlementController.java
  4. 4 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/vo/PtSettlementRespVO.java
  5. 5 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/ptsettlement/PtSettlementDO.java
  6. 40 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/data/ShopSettlementErrorData.java
  7. 51 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/data/ShopSettlementPDFData.java
  8. 112 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/file/BufferedImageMultipartFile.java
  9. 10 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/ptsettlement/PtSettlementService.java
  10. 379 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/ptsettlement/PtSettlementServiceImpl.java
  11. 9 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/shopsettlement/ShopSettlementService.java
  12. 16 1
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/shopsettlement/ShopSettlementServiceImpl.java
  13. 4 1
      sql/mysql/建空库SQL/18_20240717.sql

+ 19 - 0
feifan-module-distri/feifan-module-distri-api/src/main/java/cn/newfeifan/mall/module/distri/enums/PtSettlemntStatusEnum.java

@@ -0,0 +1,19 @@
+package cn.newfeifan.mall.module.distri.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum PtSettlemntStatusEnum {
+
+    UN_SETTLEMENT(0,"未完成"),
+    SETTLEMENT(1,"已完成"),
+    SETTLEMENT_ERROR(2,"部分完成"),
+    SETTLEMENT_SUCCESS(3,"全部失败");
+
+    private final Integer status;
+
+    private final String mark;
+
+}

+ 7 - 0
feifan-module-distri/feifan-module-distri-biz/pom.xml

@@ -124,5 +124,12 @@
             <version>2.0.0-jdk8-snapshot</version>
             <scope>compile</scope>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.24</version>
+        </dependency>
+
     </dependencies>
 </project>

+ 10 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/PtSettlementController.java

@@ -1,6 +1,7 @@
 package cn.newfeifan.mall.module.distri.controller.admin.ptsettlement;
 
 import cn.newfeifan.mall.module.distri.controller.admin.shopsettlement.vo.ShopSettlementPageReqVO;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementErrorData;
 import cn.newfeifan.mall.module.distri.service.shopsettlement.ShopSettlementService;
 import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
@@ -29,6 +30,7 @@ import static cn.newfeifan.mall.framework.operatelog.core.enums.OperateTypeEnum.
 import cn.newfeifan.mall.module.distri.controller.admin.ptsettlement.vo.*;
 import cn.newfeifan.mall.module.distri.dal.dataobject.ptsettlement.PtSettlementDO;
 import cn.newfeifan.mall.module.distri.service.ptsettlement.PtSettlementService;
+import org.springframework.web.multipart.MultipartFile;
 
 @Tag(name = "管理后台 - 平台每日结算信息表,记录店铺的结算信息")
 @RestController
@@ -108,4 +110,12 @@ public class PtSettlementController {
         ExcelUtils.write(response, "批量转账,批量转账.xls", "数据", TransferTemplateRespVO.class,list);
     }
 
+    @PostMapping("/import")
+    @Operation(summary = "导入pdf转账回执单")
+    @PreAuthorize("@ss.hasPermission('distri:pt-settlement:import')")
+    public CommonResult<List<ShopSettlementErrorData>> importPdf(@RequestParam("file") MultipartFile file, @RequestParam("id") Long id) throws IOException {
+
+        return success(ptSettlementService.importPdf(file,id));
+    }
+
 }

+ 4 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/vo/PtSettlementRespVO.java

@@ -35,4 +35,8 @@ public class PtSettlementRespVO {
     @ExcelProperty("是否结账")
     private Boolean platformTransferConfirm;
 
+    @Schema(description = "状态")
+    @ExcelProperty("状态")
+    private Integer status;
+
 }

+ 5 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/ptsettlement/PtSettlementDO.java

@@ -42,4 +42,9 @@ public class PtSettlementDO extends BaseDO {
      */
     private Boolean platformTransferConfirm;
 
+    /**
+     * 结算单状态 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败
+     */
+    private Integer status;
+
 }

+ 40 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/data/ShopSettlementErrorData.java

@@ -0,0 +1,40 @@
+package cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data;
+
+import cn.newfeifan.mall.module.distri.controller.admin.shopsettlement.vo.ShopSettlementRespVO;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 存放错误回执单信息的类
+ */
+
+@Data
+@Builder
+public class ShopSettlementErrorData {
+
+    /**
+     * 结算单id
+     */
+    private ShopSettlementRespVO shopSettlement;
+
+    /**
+     * 账号
+     */
+    private String accountNumber;
+
+    /**
+     * 户名
+     */
+    private String accountName;
+
+    /**
+     * 金额
+     */
+    private String money;
+
+    /**
+     * 订单流水号
+     */
+    private String orderNO;
+
+}

+ 51 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/data/ShopSettlementPDFData.java

@@ -0,0 +1,51 @@
+package cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data;
+
+import cn.newfeifan.mall.module.api.shop.dto.ShopDTO;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Data
+public class ShopSettlementPDFData {
+
+    /**
+     * 结算id
+     */
+    private Long id;
+    /**
+     * 店铺id
+     */
+    private Long shopId;
+    /**
+     * 商户id
+     */
+    private Long merchantId;
+    /**
+     * 销售额(积分 + 支付金额)
+     */
+    private Integer platformCollectionAmount;
+    /**
+     * 抵扣积分
+     */
+    private Long shopAmount;
+    /**
+     * 共计成本价格(高精度 + 成本)
+     */
+    private BigDecimal shopTotalHighAmount;
+    /**
+     * 平台结算ID
+     */
+    private Long ptSettlementId;
+    /**
+     * 转账凭证附件
+     */
+    private String attachment;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    private ShopDTO shop;
+}

+ 112 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/file/BufferedImageMultipartFile.java

@@ -0,0 +1,112 @@
+package cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.file;
+
+import org.jetbrains.annotations.NotNull;
+import org.springframework.core.io.Resource;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * 实现MultipartFile接口,用于将BufferedImage转换为MultipartFile对象。
+ * 这个类允许将图像数据封装为MultipartFile,以便在Spring框架中进行文件上传操作。
+ */
+public class BufferedImageMultipartFile implements MultipartFile {
+
+    private final BufferedImage bufferedImage; // 存储BufferedImage实例
+    private final String fileName; // 图像文件名
+    private final String contentType; // 图像的内容类型
+
+    /**
+     * 构造函数初始化BufferedImageMultipartFile实例。
+     *
+     * @param bufferedImage 要封装的BufferedImage实例
+     * @param fileName      图像文件名
+     * @param contentType   图像的内容类型
+     */
+    public BufferedImageMultipartFile(BufferedImage bufferedImage, String fileName, String contentType) {
+        this.bufferedImage = bufferedImage;
+        this.fileName = fileName;
+        this.contentType = contentType;
+    }
+
+    @NotNull
+    @Override
+    public String getName() {
+        return this.fileName; // 返回文件名
+    }
+
+    @Override
+    public String getOriginalFilename() {
+        return this.fileName; // 返回原始文件名,与getName相同
+    }
+
+    @Override
+    public String getContentType() {
+        return this.contentType; // 返回内容类型
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return this.bufferedImage == null; // 如果BufferedImage为空,则返回true
+    }
+
+    @Override
+    public long getSize() {
+        // 计算图像数据的大小
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+            ImageIO.write(bufferedImage, "png", bos);
+            return bos.size();
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to calculate size of the image.", e);
+        }
+    }
+
+    @NotNull
+    @Override
+    public byte[] getBytes() throws IOException {
+        // 将图像数据转换为字节数组
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+            ImageIO.write(bufferedImage, "png", bos);
+            return bos.toByteArray();
+        }
+    }
+
+    @NotNull
+    @Override
+    public InputStream getInputStream() throws IOException {
+        // 创建一个输入流,用于读取图像数据
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+            ImageIO.write(bufferedImage, "png", bos);
+            return new ByteArrayInputStream(bos.toByteArray());
+        }
+    }
+
+    @NotNull
+    @Override
+    public Resource getResource() {
+        // 不支持此方法,因为BufferedImage不能直接转换为Resource
+        throw new UnsupportedOperationException("getResource not supported.");
+    }
+
+    @Override
+    public void transferTo(@NotNull File dest) throws IOException {
+        // 将图像数据写入指定的File对象
+        try (OutputStream os = Files.newOutputStream(dest.toPath())) {
+            ImageIO.write(bufferedImage, "png", os);
+        }
+    }
+
+    @Override
+    public void transferTo(@NotNull Path dest) throws IOException {
+        // 将图像数据写入指定的Path对象
+        try (OutputStream os = Files.newOutputStream(dest)) {
+            ImageIO.write(bufferedImage, "png", os);
+        }
+    }
+
+    // 其他MultipartFile方法的实现...
+}

+ 10 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/ptsettlement/PtSettlementService.java

@@ -4,6 +4,10 @@ import javax.validation.*;
 import cn.newfeifan.mall.module.distri.controller.admin.ptsettlement.vo.*;
 import cn.newfeifan.mall.module.distri.dal.dataobject.ptsettlement.PtSettlementDO;
 import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementErrorData;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
 
 /**
  * 平台每日结算信息表,记录店铺的结算信息 Service 接口
@@ -50,4 +54,10 @@ public interface PtSettlementService {
      */
     PageResult<PtSettlementDO> getPtSettlementPage(PtSettlementPageReqVO pageReqVO);
 
+    /**
+     * 导入转账回执单
+     * @param file pdf文件
+     * @param id 每日结算单id
+     */
+    List<ShopSettlementErrorData> importPdf(MultipartFile file, Long id);
 }

+ 379 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/ptsettlement/PtSettlementServiceImpl.java

@@ -1,7 +1,20 @@
 package cn.newfeifan.mall.module.distri.service.ptsettlement;
 
+import cn.hutool.core.io.IoUtil;
+import cn.newfeifan.mall.framework.common.exception.ErrorCode;
+import cn.newfeifan.mall.module.distri.controller.admin.shopsettlement.vo.ShopSettlementRespVO;
+import cn.newfeifan.mall.module.distri.controller.admin.shopsettlement.vo.ShopSettlementSaveReqVO;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementErrorData;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementPDFData;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.file.BufferedImageMultipartFile;
+import cn.newfeifan.mall.module.distri.enums.PtSettlemntStatusEnum;
+import cn.newfeifan.mall.module.distri.service.shopsettlement.ShopSettlementService;
+import cn.newfeifan.mall.module.infra.service.file.FileService;
 import org.springframework.stereotype.Service;
+
 import javax.annotation.Resource;
+
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import cn.newfeifan.mall.module.distri.controller.admin.ptsettlement.vo.*;
@@ -14,6 +27,22 @@ import cn.newfeifan.mall.module.distri.dal.mysql.ptsettlement.PtSettlementMapper
 import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;
 
+import org.springframework.web.multipart.MultipartFile;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.rendering.PDFRenderer;
+import org.apache.pdfbox.text.PDFTextStripper;
+
+import java.awt.image.BufferedImage;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+
 /**
  * 平台每日结算信息表,记录店铺的结算信息 Service 实现类
  *
@@ -26,6 +55,12 @@ public class PtSettlementServiceImpl implements PtSettlementService {
     @Resource
     private PtSettlementMapper ptSettlementMapper;
 
+    @Resource
+    private ShopSettlementService shopSettlementService;
+
+    @Resource
+    private FileService fileService;
+
     @Override
     public Long createPtSettlement(PtSettlementSaveReqVO createReqVO) {
         // 插入
@@ -74,4 +109,348 @@ public class PtSettlementServiceImpl implements PtSettlementService {
         return result;
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public List<ShopSettlementErrorData> importPdf(MultipartFile multipartFile, Long id) {
+        // 定义日期格式,只包含年月日
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+        // 校验文件格式
+        if (!isPdf(multipartFile)) {
+            ErrorCode ERROR = new ErrorCode(1_002_030_026, "选择的文件不是pdf格式");
+            throw exception(ERROR);
+        }
+
+        // 获取选择日期,店铺的结算信息
+        List<ShopSettlementPDFData> shopSettList = shopSettlementService.selectListByPtId(id);
+
+        if (shopSettList.isEmpty()) {
+            ErrorCode ERROR = new ErrorCode(1_002_030_027, "选择的行中没有结算单记录");
+            throw exception(ERROR);
+        }
+
+        // 用来记录错误的回执单信息
+        List<ShopSettlementErrorData> errorList = new ArrayList<>();
+
+        try {
+            // 将MultipartFile转换为临时文件
+            Path tempFile = Files.createTempFile("temp", ".pdf");
+            multipartFile.transferTo(tempFile.toFile());
+
+            // 加载指定路径的PDF文档
+            PDDocument document = PDDocument.load(tempFile.toFile());
+
+            // 创建PDF渲染器,用于将PDF页面渲染为图像
+            PDFRenderer pdfRenderer = new PDFRenderer(document);
+
+            // 创建PDF文本剥离器,用于从PDF页面中提取文本
+            PDFTextStripper textStripper = new PDFTextStripper();
+
+            // 遍历文档中的每一页
+            for (int pageIndex = 0; pageIndex < document.getNumberOfPages(); pageIndex++) {
+
+                // 设置开始和结束页码,以便仅从当前页提取文本
+                textStripper.setStartPage(pageIndex + 1);
+                textStripper.setEndPage(pageIndex + 1);
+
+                // 提取当前页的文本
+                String pageText = textStripper.getText(document);
+
+                // 检查页面是否包含错误信息
+                if (containsErrorInfo(pageText)) {
+
+                    // 账号
+                    String accountNumber = getErrorAccountNumber(pageText, true);
+                    // 户名
+                    String accountName = getErrorAccountName(pageText, true);
+                    // 金额
+                    String money = getMoney(pageText);
+                    // 订单流水号
+                    String orderNO = getOrderNO(pageText);
+
+                    ShopSettlementErrorData error = ShopSettlementErrorData.builder()
+                            .accountNumber(accountNumber)
+                            .accountName(accountName)
+                            .money(money)
+                            .orderNO(orderNO)
+                            .build();
+
+                    errorList.add(error);
+                    continue;
+                }
+
+                // 判断备注的账单日期是否与结算单为同一天
+                String time = getOrderTime(pageText);
+                if (time != null && !time.isEmpty()) {
+                    for (ShopSettlementPDFData shopSettlementPDFData : shopSettList) {
+                        // 判断日期是否同样
+                        isSameDate(shopSettlementPDFData, formatter, time);
+                    }
+                }
+
+                for (ShopSettlementPDFData shopSettlementPDFData : shopSettList) {
+                    // 账号
+                    String accountNumber = getErrorAccountNumber(pageText, false);
+                    // 户名
+                    String accountName = getErrorAccountName(pageText, false);
+                    // 金额
+                    String money = getMoney(pageText);
+
+                    if (shopSettlementPDFData.getShop().getAccountNumber().equals(accountNumber) &&
+                            shopSettlementPDFData.getShop().getAccountName().equals(accountName) &&
+                            shopSettlementPDFData.getShopTotalHighAmount().divide(new BigDecimal("100"), 2, RoundingMode.FLOOR).toString().equals(money)) {
+
+                        BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 300);
+                        int desiredHeight = 1200; // 设定你想要的高度
+
+                        // 获取原始宽度和高度
+                        int originalWidth = image.getWidth();
+                        int originalHeight = image.getHeight();
+
+                        // 计算裁剪区域的宽度和高度
+                        int cropWidth = originalWidth;
+                        int cropHeight = desiredHeight;
+
+                        // 确保裁剪区域不会超出原图范围
+                        if (cropHeight > originalHeight) {
+                            cropHeight = originalHeight;
+                        }
+
+                        // 计算裁剪区域的起始点,这里我们假设从顶部开始裁剪
+                        int x = 0;
+                        int y = 0;
+
+                        // 裁剪图片
+                        BufferedImage croppedImage = image.getSubimage(x, y, cropWidth, cropHeight);
+
+                        String fileName = "image.png";
+                        String contentType = "image/png";
+
+                        MultipartFile file = new BufferedImageMultipartFile(croppedImage, fileName, contentType);
+
+                        // 上传文件
+                        String fileUrl = fileService.createFile(file.getOriginalFilename(), null, IoUtil.readBytes(file.getInputStream()));
+
+                        ShopSettlementSaveReqVO bean = BeanUtils.toBean(shopSettlementPDFData, ShopSettlementSaveReqVO.class);
+                        bean.setAttachment(fileUrl);
+
+                        // 保存修改结算单
+                        shopSettlementService.updateShopSettlement(bean);
+                    }
+                }
+            }
+
+            // 回退错误的回执单导致的结算单信息
+            if (!errorList.isEmpty()) {
+
+                for (ShopSettlementErrorData shopSettlementErrorData : errorList) {
+
+                    for (ShopSettlementPDFData shopSettlementPDFData : shopSettList) {
+
+                        if (shopSettlementPDFData.getShop().getAccountNumber().equals(shopSettlementErrorData.getAccountNumber()) &&
+                                shopSettlementPDFData.getShop().getAccountName().equals(shopSettlementErrorData.getAccountName()) &&
+                                shopSettlementPDFData.getShopTotalHighAmount().divide(new BigDecimal("100"), 2, RoundingMode.FLOOR).toString().equals(shopSettlementErrorData.getMoney())
+                        ) {
+                            ShopSettlementSaveReqVO bean = BeanUtils.toBean(shopSettlementPDFData, ShopSettlementSaveReqVO.class);
+                            bean.setAttachment(null);
+
+                            shopSettlementErrorData.setShopSettlement(BeanUtils.toBean(bean, ShopSettlementRespVO.class));
+
+                            shopSettlementService.updateShopSettlement(bean);
+                        }
+                    }
+                }
+            }
+
+            boolean status = true;
+            for (ShopSettlementPDFData shopSettlementPDFData : shopSettList) {
+                if (shopSettlementPDFData.getAttachment() == null) {
+                    status = false;
+                }
+            }
+
+            PtSettlementDO ptSettlementDO = ptSettlementMapper.selectById(id);
+            if (status) {
+                ptSettlementDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT.getStatus());
+            } else {
+                ptSettlementDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT_ERROR.getStatus());
+            }
+
+            // 如果错误的回执单数量和结算单数量一致,则说明全部失败
+            if (errorList.size() == shopSettList.size()) {
+                ptSettlementDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT_SUCCESS.getStatus());
+            }
+
+            // 更新pt结算单状态
+            ptSettlementMapper.updateById(ptSettlementDO);
+
+            // 关闭PDF文档
+            document.close();
+        } catch (Exception e) {
+            ErrorCode ERROR = new ErrorCode(1_002_030_027, "处理PDF文件异常: " + e.getMessage());
+            throw exception(ERROR);
+        }
+
+        return errorList;
+    }
+
+    /**
+     * 判断备注的账单日期是否与结算单为同一天
+     *
+     * @param shopSettlementPDFData 结算单
+     * @param formatter             日期格式
+     * @param time                  日期
+     */
+    private void isSameDate(ShopSettlementPDFData shopSettlementPDFData, DateTimeFormatter formatter, String time) {
+        // 使用定义的格式器格式化LocalDateTime对象
+        String formattedDate = shopSettlementPDFData.getCreateTime().minusDays(1).format(formatter);
+
+        if (!time.equals(formattedDate)) {
+            ErrorCode ERROR = new ErrorCode(1_002_030_028, "上传的PDF文件中有回执单日期与结算单日期不同!");
+            throw exception(ERROR);
+        }
+    }
+
+    /**
+     * 获取回执单的备注:账单日期
+     *
+     * @param pageText 回执单文本
+     * @return 账单日期
+     */
+    private String getOrderTime(String pageText) {
+        int timeIndex = pageText.indexOf("账单日期:");
+
+        if (timeIndex == -1) {
+            return null;
+        }
+
+        timeIndex = timeIndex + "账单日期:".length();
+
+        int timeEndIndex = pageText.indexOf("温馨提示");
+
+        return pageText.substring(timeIndex, timeEndIndex).trim();
+    }
+
+    /**
+     * 获取错误的回执单流水号
+     *
+     * @param pageText 回执单文本
+     * @return 流水号
+     */
+    private String getOrderNO(String pageText) {
+
+        int NOIndex = pageText.indexOf("关联正向交易账务流水号:");
+        NOIndex = NOIndex + "关联正向交易账务流水号:".length();
+
+        int NOEndIndex = pageText.indexOf("温馨提示");
+
+        return pageText.substring(NOIndex, NOEndIndex).trim();
+    }
+
+    /**
+     * 获取错误的回执单户名
+     *
+     * @param pageText 回执单文本
+     * @param isError  是否是错误类型
+     * @return 户名
+     */
+    private String getErrorAccountName(String pageText, boolean isError) {
+
+        if (isError) {
+            int nameIndex = pageText.indexOf("户名");
+            nameIndex = nameIndex + "户名".length();
+
+            int nameEndIndex = pageText.indexOf("收");
+
+            return pageText.substring(nameIndex, nameEndIndex).trim();
+        } else {
+            int nameIndex = pageText.lastIndexOf("户名");
+            nameIndex = nameIndex + "户名".length();
+
+            int nameEndIndex = pageText.indexOf("账号");
+
+            return pageText.substring(nameIndex, nameEndIndex).trim();
+        }
+    }
+
+
+    /**
+     * 获取错误的回执单账号
+     *
+     * @param pageText 回执单文本
+     * @param isError  是否是错误类型
+     * @return 账号
+     */
+    private String getErrorAccountNumber(String pageText, boolean isError) {
+
+        // 错误的回执单和正确的回执单截取的位置不同
+        if (isError) {
+            int accountNumberIndex = pageText.indexOf("账号");
+            accountNumberIndex = accountNumberIndex + "账号".length();
+
+            int accountNumberEndIndex = pageText.lastIndexOf("账号");
+
+            return pageText.substring(accountNumberIndex, accountNumberEndIndex).trim();
+        } else {
+            int accountNumberIndex = pageText.lastIndexOf("账号");
+            accountNumberIndex = accountNumberIndex + "账号".length();
+
+            int accountNumberEndIndex = pageText.indexOf("机构");
+
+            return pageText.substring(accountNumberIndex, accountNumberEndIndex).trim();
+        }
+    }
+
+    /**
+     * 获取回执单中的金额
+     *
+     * @param pageText 回执单文本
+     * @return 金额
+     */
+    private String getMoney(String pageText) {
+        int rmbIndex = pageText.indexOf("人民币");
+        rmbIndex = rmbIndex + "人民币".length();
+        int payTimeIndex = pageText.indexOf("交易时间");
+
+        return pageText.substring(rmbIndex, payTimeIndex).trim();
+    }
+
+    /**
+     * 检查给定的页面文本是否包含错误信息的字样
+     *
+     * @param pageText 要检查的页面文本
+     * @return 如果页面文本包含"关联正向交易账务流水号",则返回true;否则返回false
+     */
+    private static boolean containsErrorInfo(String pageText) {
+        return pageText.contains("关联正向交易账务流水号");
+    }
+
+    public boolean isPdf(MultipartFile file) {
+        // Check file extension
+        String originalFilename = file.getOriginalFilename();
+        if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".pdf")) {
+            System.out.println("文件不是PDF格式,扩展名不符合要求");
+            return false;
+        }
+
+//        // Optionally, check file header for added security
+//        try {
+//            byte[] headerBytes = new byte[4];
+//            try (InputStream is = file.getInputStream()) {
+//                is.read(headerBytes, 0, headerBytes.length);
+//            }
+//            String header = new String(headerBytes);
+//            if (!header.equals("%PDF-")) {
+//                System.out.println("文件不是PDF格式,文件头不符合要求");
+//                return false;
+//            }
+//        } catch (IOException e) {
+//            System.out.println("读取文件头时发生错误:" + e.getMessage());
+//            return false;
+//        }
+
+        return true;
+    }
+
+
 }

+ 9 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/shopsettlement/ShopSettlementService.java

@@ -6,6 +6,7 @@ import cn.newfeifan.mall.module.distri.controller.admin.ptsettlement.vo.Transfer
 import cn.newfeifan.mall.module.distri.controller.admin.shopsettlement.vo.*;
 import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.ShopSettlementDO;
 import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementPDFData;
 
 import java.util.List;
 
@@ -66,4 +67,12 @@ public interface ShopSettlementService {
      * 结算已确权订单(也是按照每个店铺)
      */
     void settlementOrder();
+
+
+    /**
+     * 根据平台id查询
+     * @param id ptID
+     * @return 店铺结算信息
+     */
+    List<ShopSettlementPDFData> selectListByPtId(Long id);
 }

+ 16 - 1
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/shopsettlement/ShopSettlementServiceImpl.java

@@ -7,6 +7,7 @@ import cn.newfeifan.mall.module.distri.controller.admin.ptsettlement.vo.Transfer
 import cn.newfeifan.mall.module.distri.dal.dataobject.orderitemsettlement.OrderItemSettlementDO;
 import cn.newfeifan.mall.module.distri.dal.dataobject.ordersettlement.OrderSettlementDO;
 import cn.newfeifan.mall.module.distri.dal.dataobject.ptsettlement.PtSettlementDO;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementPDFData;
 import cn.newfeifan.mall.module.distri.dal.mysql.dailybill.DailyBillMapper;
 import cn.newfeifan.mall.module.distri.dal.mysql.orderitemsettlement.OrderItemSettlementMapper;
 import cn.newfeifan.mall.module.distri.dal.mysql.ordersettlement.OrderSettlementMapper;
@@ -130,7 +131,7 @@ public class ShopSettlementServiceImpl implements ShopSettlementService {
                     .payeeName(shop.getAccountName())
                     .payeeAccount(shop.getAccountNumber())
                     .payeeBankName(shop.getBankName())
-                    .money(respVO.getShopTotalHighAmount().divide(BigDecimal.valueOf(DistriConstants.ONE_HUNDRED), 2, RoundingMode.HALF_UP).toString())
+                    .money(respVO.getShopTotalHighAmount().divide(BigDecimal.valueOf(DistriConstants.ONE_HUNDRED), 2, RoundingMode.FLOOR).toString())
                     .mark("账单日期: " + formatter.format(respVO.getCreateTime().minusDays(1)))
                     .build());
         }
@@ -273,4 +274,18 @@ public class ShopSettlementServiceImpl implements ShopSettlementService {
         });
 
     }
+
+    @Override
+    public List<ShopSettlementPDFData> selectListByPtId(Long id) {
+        List<ShopSettlementDO> shopSettlementDOS = shopSettlementMapper.selectList(ShopSettlementDO::getPtSettlementId, id);
+        List<ShopSettlementPDFData> list = new ArrayList<>();
+
+        for (ShopSettlementDO settlementDO : shopSettlementDOS) {
+            ShopSettlementPDFData bean = BeanUtils.toBean(settlementDO, ShopSettlementPDFData.class);
+            bean.setShop(shopApi.getShop(settlementDO.getShopId()));
+            list.add(bean);
+        }
+
+        return list;
+    }
 }

+ 4 - 1
sql/mysql/建空库SQL/18_20240717.sql

@@ -57,4 +57,7 @@ CREATE TABLE `distri_pt_daily_withdrawal` (
 ALTER TABLE sale_shop
     ADD COLUMN `account_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT null COMMENT '账户名称',
 		ADD COLUMN `account_number` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT null COMMENT '账户号码',
-		ADD COLUMN `bank_name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT null COMMENT '开户银行';
+		ADD COLUMN `bank_name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT null COMMENT '开户银行';
+
+ALTER TABLE trade_pt_settlement
+    ADD COLUMN `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '结算单状态 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败';