Răsfoiți Sursa

Merge branch 'dev/2024/0719/update-admin-Y' of feifan/mall-backend-admin into master

导入提现明细
Yangzw 8 luni în urmă
părinte
comite
d79aee08c6
32 a modificat fișierele cu 963 adăugiri și 16 ștergeri
  1. 1 0
      feifan-module-distri/feifan-module-distri-api/src/main/java/cn/newfeifan/mall/module/distri/enums/CaclEnum.java
  2. 19 0
      feifan-module-distri/feifan-module-distri-api/src/main/java/cn/newfeifan/mall/module/distri/enums/PtSettlemntStatusEnum.java
  3. 21 0
      feifan-module-distri/feifan-module-distri-api/src/main/java/cn/newfeifan/mall/module/distri/enums/WithdrawalResultEnum.java
  4. 7 0
      feifan-module-distri/feifan-module-distri-biz/pom.xml
  5. 13 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelController.java
  6. 41 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelImportExcelVO.java
  7. 2 2
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelPageReqVO.java
  8. 3 3
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelRespVO.java
  9. 2 2
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelSaveReqVO.java
  10. 19 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/PtSettlementController.java
  11. 3 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/vo/PtSettlementPageReqVO.java
  12. 6 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/vo/PtSettlementRespVO.java
  13. 3 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/ptsettlement/vo/PtSettlementSaveReqVO.java
  14. 5 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/shopsettlement/vo/ShopSettlementSaveReqVO.java
  15. 2 2
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelDO.java
  16. 10 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/ptsettlement/PtSettlementDO.java
  17. 8 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/ShopSettlementDO.java
  18. 40 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/data/ShopSettlementErrorData.java
  19. 51 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/data/ShopSettlementPDFData.java
  20. 112 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/file/BufferedImageMultipartFile.java
  21. 12 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/mysql/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelMapper.java
  22. 4 2
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/mysql/ptprofitlog/PtProfitLogMapper.java
  23. 7 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/applicationforwithdrawal/ApplicationForWithdrawalService.java
  24. 5 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/applicationforwithdrawal/ApplicationForWithdrawalServiceImpl.java
  25. 9 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelService.java
  26. 126 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelServiceImpl.java
  27. 10 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/ptsettlement/PtSettlementService.java
  28. 389 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/ptsettlement/PtSettlementServiceImpl.java
  29. 8 0
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/shopsettlement/ShopSettlementService.java
  30. 10 1
      feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/shopsettlement/ShopSettlementServiceImpl.java
  31. 1 0
      feifan-module-system/feifan-module-system-api/src/main/java/cn/newfeifan/mall/module/system/enums/sms/SmsSceneEnum.java
  32. 14 4
      sql/mysql/建空库SQL/18_20240717.sql

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

@@ -31,6 +31,7 @@ public enum CaclEnum {
     ORDER_REFUND_ORDER_PAY_FREEZE_HIGH_QUOTA(24, "订单退款-撤回峰值奖","消费者购物,获得冻结峰值"),
     MANUAL_RETURN_INTEGRAL(25, "人工返回最早七天未获得的超出额度的合赢奖","人工返回最早七天未获得的合赢奖,超额的"),
     WITHDRAWAL(26, "用户提现","用户将可用积分提现到账户"),
+    WITHDRAWAL_ERROR(27, "提现失败退回","提现失败退回积分到用户"),
     ;
 
     /**

+ 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;
+
+}

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

@@ -0,0 +1,21 @@
+package cn.newfeifan.mall.module.distri.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 提现结果枚举
+ */
+
+@Getter
+@AllArgsConstructor
+public enum WithdrawalResultEnum {
+
+    SUCCESS("SUCCESS","交易成功"),
+    FAIL("FAIL","交易失败"),
+    ;
+
+    private final String result;
+
+    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>

+ 13 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelController.java

@@ -27,6 +27,7 @@ import static cn.newfeifan.mall.framework.operatelog.core.enums.OperateTypeEnum.
 import cn.newfeifan.mall.module.distri.controller.admin.applicationforwithdrawalchannel.vo.*;
 import cn.newfeifan.mall.module.distri.dal.dataobject.applicationforwithdrawalchannel.ApplicationForWithdrawalChannelDO;
 import cn.newfeifan.mall.module.distri.service.applicationforwithdrawalchannel.ApplicationForWithdrawalChannelService;
+import org.springframework.web.multipart.MultipartFile;
 
 @Tag(name = "管理后台 - 提现渠道记录")
 @RestController
@@ -96,4 +97,16 @@ public class ApplicationForWithdrawalChannelController {
         ExcelUtils.write(response, "提现记录.xls", "数据", ApplicationForWithdrawalChannelExcelRespVO.class, list);
     }
 
+    @PostMapping("/import")
+    @Operation(summary = "导入提现明细, excel表")
+    @PreAuthorize("@ss.hasPermission('distri:application-for-withdrawal-channel:import')")
+    public CommonResult<List<ApplicationForWithdrawalChannelImportExcelVO>> importExcel(@RequestParam("file") MultipartFile file, @RequestParam("id") Long id) throws Exception{
+
+        List<ApplicationForWithdrawalChannelImportExcelVO> list = ExcelUtils.read(file, ApplicationForWithdrawalChannelImportExcelVO.class);
+
+
+
+        return success(applicationForWithdrawalChannelService.importExcel(list,id));
+    }
+
 }

+ 41 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelImportExcelVO.java

@@ -0,0 +1,41 @@
+package cn.newfeifan.mall.module.distri.controller.admin.applicationforwithdrawalchannel.vo;
+
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+
+/**
+ * 提现明细 Excel 导入 VO
+ */
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
+public class ApplicationForWithdrawalChannelImportExcelVO {
+
+    @ExcelProperty("收款方名称")
+    private String accountName;
+
+    @ExcelProperty("收款方账号")
+    private String accountNumber;
+
+    @ExcelProperty("金额")
+    private String money;
+
+    @ExcelProperty("附言/用途")
+    private String postscript;
+
+    @ExcelProperty("交易结果")
+    private String payResult;
+
+    @ExcelProperty("交易描述")
+    private String payDescription;
+
+}

+ 2 - 2
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelPageReqVO.java

@@ -26,8 +26,8 @@ public class ApplicationForWithdrawalChannelPageReqVO extends PageParam {
     @Schema(description = "提现笔数", example = "6693")
     private Integer count;
 
-    @Schema(description = "提现状态,已完成是1,未完成为0", example = "1")
-    private Boolean status;
+    @Schema(description = "提现状态, 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败", example = "1")
+    private Integer status;
 
     @Schema(description = "提现渠道记录id", example = "14600")
     private Long ptDailyWithdrawalId;

+ 3 - 3
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelRespVO.java

@@ -30,9 +30,9 @@ public class ApplicationForWithdrawalChannelRespVO {
     @ExcelProperty("提现笔数")
     private Integer count;
 
-    @Schema(description = "提现状态,已完成是1,未完成为0", example = "1")
-    @ExcelProperty("提现状态,已完成是1,未完成为0")
-    private Boolean status;
+    @Schema(description = "提现状态, 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败", example = "1")
+    @ExcelProperty("提现状态, 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败")
+    private Integer status;
 
     @Schema(description = "提现渠道记录id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14600")
     @ExcelProperty("提现渠道记录id")

+ 2 - 2
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/applicationforwithdrawalchannel/vo/ApplicationForWithdrawalChannelSaveReqVO.java

@@ -27,8 +27,8 @@ public class ApplicationForWithdrawalChannelSaveReqVO {
     @NotNull(message = "提现笔数不能为空")
     private Integer count;
 
-    @Schema(description = "提现状态,已完成是1,未完成为0", example = "1")
-    private Boolean status;
+    @Schema(description = "提现状态, 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败", example = "1")
+    private Integer status;
 
     @Schema(description = "提现渠道记录id", requiredMode = Schema.RequiredMode.REQUIRED, example = "14600")
     @NotNull(message = "提现渠道记录id不能为空")

+ 19 - 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
@@ -103,9 +105,26 @@ public class PtSettlementController {
     public void exportPtSettlementExcelTransferTemplate(@Valid ShopSettlementPageReqVO pageReqVO,
                                         HttpServletResponse response) throws IOException {
         pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+
         List<TransferTemplateRespVO> list = shopSettlementService.excelShopSettlementPage(pageReqVO);
+
+        if(!list.isEmpty()){
+            PtSettlementDO ptSettlement = ptSettlementService.getPtSettlement(pageReqVO.getPtSettlementId());
+
+            ptSettlement.setExportStatus(true);
+            ptSettlementService.updatePtSettlement(BeanUtils.toBean(ptSettlement, PtSettlementSaveReqVO.class));
+        }
+
         // 导出 Excel
         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));
+    }
+
 }

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

@@ -31,4 +31,7 @@ public class PtSettlementPageReqVO extends PageParam {
     @Schema(description = "是否结账")
     private Boolean platformTransferConfirm;
 
+    @Schema(description = "导出状态,已导出是1,未导出为0", example = "1")
+    private Boolean exportStatus;
+
 }

+ 6 - 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,10 @@ public class PtSettlementRespVO {
     @ExcelProperty("是否结账")
     private Boolean platformTransferConfirm;
 
+    @Schema(description = "状态")
+    @ExcelProperty("状态")
+    private Integer status;
+
+    @Schema(description = "导出状态,已导出是1,未导出为0", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Boolean exportStatus;
 }

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

@@ -26,4 +26,7 @@ public class PtSettlementSaveReqVO {
     @Schema(description = "是否结账")
     private Boolean platformTransferConfirm;
 
+    @Schema(description = "导出状态,已导出是1,未导出为0", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Boolean exportStatus;
+
 }

+ 5 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/controller/admin/shopsettlement/vo/ShopSettlementSaveReqVO.java

@@ -38,4 +38,9 @@ public class ShopSettlementSaveReqVO {
     @Schema(description = "转账凭证附件")
     private String attachment;
 
+    @Schema(description = "账户名称", example = "张三")
+    private String accountName;
+
+    @Schema(description = "账户号码")
+    private String accountNumber;
 }

+ 2 - 2
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelDO.java

@@ -41,9 +41,9 @@ public class ApplicationForWithdrawalChannelDO extends BaseDO {
      */
     private Integer count;
     /**
-     * 提现状态,已完成是1,未完成为0
+     * 提现状态, 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败
      */
-    private Boolean status;
+    private Integer status;
     /**
      * 提现渠道记录id
      */

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

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

+ 8 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/dataobject/shopsettlement/ShopSettlementDO.java

@@ -53,5 +53,13 @@ public class ShopSettlementDO extends BaseDO {
      * 转账凭证附件
      */
     private String attachment;
+    /**
+     * 账户名称
+     */
+    private String accountName;
+    /**
+     * 账户号码
+     */
+    private String accountNumber;
 
 }

+ 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方法的实现...
+}

+ 12 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/mysql/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelMapper.java

@@ -28,4 +28,16 @@ public interface ApplicationForWithdrawalChannelMapper extends BaseMapperX<Appli
                 .orderByDesc(ApplicationForWithdrawalChannelDO::getId));
     }
 
+    /**
+     * 获取提现渠道记录
+     * @param status 状态
+     * @param ptDailyWithdrawalId 一级提现记录id
+     * @return 记录条数
+     */
+    default Long selectCount(Integer status, Long ptDailyWithdrawalId){
+        return selectCount(new LambdaQueryWrapperX<ApplicationForWithdrawalChannelDO>()
+                .eq(ApplicationForWithdrawalChannelDO::getStatus, status)
+                .eq(ApplicationForWithdrawalChannelDO::getPtDailyWithdrawalId, ptDailyWithdrawalId)
+        );
+    }
 }

+ 4 - 2
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/dal/mysql/ptprofitlog/PtProfitLogMapper.java

@@ -40,7 +40,8 @@ public interface PtProfitLogMapper extends BaseMapperX<PtProfitLogDO> {
                 ORDER_PAY_FREEZE_HIGH_QUOTA.getType(),
                 ORDER_REFUND_ORDER_PAY_FREEZE_HIGH_QUOTA.getType(),
                 MANUAL_RETURN_INTEGRAL.getType(),
-                WITHDRAWAL.getType()
+                WITHDRAWAL.getType(),
+                WITHDRAWAL_ERROR.getType()
         );
 
         if(reqVO.getUserId().equals(PT_ID)){
@@ -62,7 +63,8 @@ public interface PtProfitLogMapper extends BaseMapperX<PtProfitLogDO> {
                     ORDER_CANCEL_BY_SYSTEM_REFUND_INTEGRAL.getType(),
                     ORDER_PAY_FREEZE_HIGH_QUOTA.getType(),
                     ORDER_REFUND_ORDER_PAY_FREEZE_HIGH_QUOTA.getType(),
-                    WITHDRAWAL.getType()
+                    WITHDRAWAL.getType(),
+                    WITHDRAWAL_ERROR.getType()
             );
 //            reqVO.setUserId(null);
         }

+ 7 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/applicationforwithdrawal/ApplicationForWithdrawalService.java

@@ -58,4 +58,11 @@ public interface ApplicationForWithdrawalService {
      * @return 提现记录
      */
     List<ApplicationForWithdrawalChannelExcelRespVO> getApplicationForWithdrawalChannelPage(Long id);
+
+    /**
+     * 获得提现申请记录
+     * @param id 通道记录id
+     * @return 提现记录
+     */
+    List<ApplicationForWithdrawalDO> selectListByChannelId(Long id);
 }

+ 5 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/applicationforwithdrawal/ApplicationForWithdrawalServiceImpl.java

@@ -111,4 +111,9 @@ public class ApplicationForWithdrawalServiceImpl implements ApplicationForWithdr
         return list;
     }
 
+    @Override
+    public List<ApplicationForWithdrawalDO> selectListByChannelId(Long id) {
+        return applicationForWithdrawalMapper.selectList(ApplicationForWithdrawalDO::getApplicationForWithdrawalChannelId,id, ApplicationForWithdrawalDO::getStatus,0);
+    }
+
 }

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

@@ -5,6 +5,8 @@ import cn.newfeifan.mall.module.distri.controller.admin.applicationforwithdrawal
 import cn.newfeifan.mall.module.distri.dal.dataobject.applicationforwithdrawalchannel.ApplicationForWithdrawalChannelDO;
 import cn.newfeifan.mall.framework.common.pojo.PageResult;
 
+import java.util.List;
+
 /**
  * 提现渠道记录 Service 接口
  *
@@ -56,4 +58,11 @@ public interface ApplicationForWithdrawalChannelService {
      * @param id 编号
      */
     void updateApplicationForWithdrawalChannel(Long id);
+
+    /**
+     * 导入提现明细, excel表
+     * @param list 明细
+     * @param id 通道id
+     */
+    List<ApplicationForWithdrawalChannelImportExcelVO> importExcel(List<ApplicationForWithdrawalChannelImportExcelVO> list, Long id);
 }

+ 126 - 0
feifan-module-distri/feifan-module-distri-biz/src/main/java/cn/newfeifan/mall/module/distri/service/applicationforwithdrawalchannel/ApplicationForWithdrawalChannelServiceImpl.java

@@ -1,7 +1,23 @@
 package cn.newfeifan.mall.module.distri.service.applicationforwithdrawalchannel;
 
+import cn.newfeifan.mall.framework.common.exception.ErrorCode;
+import cn.newfeifan.mall.module.distri.controller.admin.applicationforwithdrawal.vo.ApplicationForWithdrawalSaveReqVO;
+import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.IntegralSaveReqVO;
+import cn.newfeifan.mall.module.distri.controller.admin.ptdailywithdrawal.vo.PtDailyWithdrawalSaveReqVO;
+import cn.newfeifan.mall.module.distri.controller.admin.ptprofitlog.vo.PtProfitLogSaveReqVO;
+import cn.newfeifan.mall.module.distri.dal.dataobject.applicationforwithdrawal.ApplicationForWithdrawalDO;
+import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
+import cn.newfeifan.mall.module.distri.dal.dataobject.ptdailywithdrawal.PtDailyWithdrawalDO;
+import cn.newfeifan.mall.module.distri.enums.PtSettlemntStatusEnum;
+import cn.newfeifan.mall.module.distri.enums.WithdrawalResultEnum;
+import cn.newfeifan.mall.module.distri.service.applicationforwithdrawal.ApplicationForWithdrawalService;
+import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
+import cn.newfeifan.mall.module.distri.service.ptdailywithdrawal.PtDailyWithdrawalService;
+import cn.newfeifan.mall.module.distri.service.ptprofitlog.PtProfitLogService;
 import org.springframework.stereotype.Service;
+
 import javax.annotation.Resource;
+
 import org.springframework.validation.annotation.Validated;
 import cn.newfeifan.mall.module.distri.controller.admin.applicationforwithdrawalchannel.vo.*;
 import cn.newfeifan.mall.module.distri.dal.dataobject.applicationforwithdrawalchannel.ApplicationForWithdrawalChannelDO;
@@ -10,7 +26,12 @@ import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
 
 import cn.newfeifan.mall.module.distri.dal.mysql.applicationforwithdrawalchannel.ApplicationForWithdrawalChannelMapper;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.newfeifan.mall.module.distri.constant.DistriConstants.MILLION;
+import static cn.newfeifan.mall.module.distri.enums.CaclEnum.WITHDRAWAL_ERROR;
 import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;
 
 /**
@@ -25,6 +46,18 @@ public class ApplicationForWithdrawalChannelServiceImpl implements ApplicationFo
     @Resource
     private ApplicationForWithdrawalChannelMapper applicationForWithdrawalChannelMapper;
 
+    @Resource
+    private ApplicationForWithdrawalService withdrawalService;
+
+    @Resource
+    private PtDailyWithdrawalService ptDailyWithdrawalService;
+
+    @Resource
+    private IntegralService integralService;
+
+    @Resource
+    private PtProfitLogService ptProfitLogService;
+
     @Override
     public Long createApplicationForWithdrawalChannel(ApplicationForWithdrawalChannelSaveReqVO createReqVO) {
         // 插入
@@ -76,4 +109,97 @@ public class ApplicationForWithdrawalChannelServiceImpl implements ApplicationFo
         applicationForWithdrawalChannelMapper.updateById(channel);
     }
 
+    @Override
+    public List<ApplicationForWithdrawalChannelImportExcelVO> importExcel(List<ApplicationForWithdrawalChannelImportExcelVO> list, Long id) {
+        // 用来记录错误的记录
+        List<ApplicationForWithdrawalChannelImportExcelVO> errorList = new ArrayList<>();
+
+        List<ApplicationForWithdrawalDO> withdrawalList = withdrawalService.selectListByChannelId(id);
+
+        // 异常判断
+        if (withdrawalList.isEmpty()) {
+            ErrorCode ERROR = new ErrorCode(1_002_030_034, "选中行的记录为空");
+            throw exception(ERROR);
+        }
+        if (list.isEmpty()) {
+            ErrorCode ERROR = new ErrorCode(1_002_030_035, "上传的Excel文件中没有数据");
+            throw exception(ERROR);
+        }
+
+        for (ApplicationForWithdrawalChannelImportExcelVO importVO : list) {
+
+            for (ApplicationForWithdrawalDO withdrawalDO : withdrawalList) {
+
+                // 当前提提现记录的金额和账号与Excel中的金额和账号一致时
+                if (withdrawalDO.getAmount().toString().equals(importVO.getMoney()) &&
+                        withdrawalDO.getWithdrawalAccount().equals(importVO.getAccountNumber())) {
+
+                    if(importVO.getPayResult().equals(WithdrawalResultEnum.SUCCESS.getResult())){
+                        withdrawalDO.setStatus(true);
+                    }else{
+                        withdrawalDO.setStatus(false);
+                        // 记录提现失败的记录
+                        errorList.add(importVO);
+
+                        // 退回用户提现积分数量
+                        IntegralDO integralDO = integralService.selectByUser(withdrawalDO.getUserId());
+                        Long integral = Long.parseLong(importVO.getMoney()) * MILLION;
+
+                        integralDO.setCurrentQuota(integralDO.getCurrentQuota() + integral);
+                        integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));
+
+                        // 添加用户积分变动Log
+                        PtProfitLogSaveReqVO ptProfitLogSaveReqVO = PtProfitLogSaveReqVO.builder()
+                                .amount(integral)
+                                .afterAmount(integralDO.getCurrentQuota())
+                                .profitStatus(WITHDRAWAL_ERROR.getType())
+                                .userId(withdrawalDO.getUserId())
+                                .generateUserId(integralDO.getUserId())
+                                .build();
+                        ptProfitLogService.createPtProfitLog(ptProfitLogSaveReqVO);
+
+                        // 发送短信通知用户提现失败
+                    }
+
+                    withdrawalService.updateApplicationForWithdrawal(BeanUtils.toBean(withdrawalDO, ApplicationForWithdrawalSaveReqVO.class));
+
+                }
+            }
+        }
+
+        ApplicationForWithdrawalChannelDO applicationForWithdrawalChannelDO = applicationForWithdrawalChannelMapper.selectById(id);
+
+        // 根据导入的记录判断提现结果
+        if(errorList.isEmpty()){
+            applicationForWithdrawalChannelDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT.getStatus());
+        }else if (errorList.size() < withdrawalList.size()){
+            applicationForWithdrawalChannelDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT_ERROR.getStatus());
+        }else if(errorList.size() == withdrawalList.size()){
+            applicationForWithdrawalChannelDO.setStatus(PtSettlemntStatusEnum.SETTLEMENT_SUCCESS.getStatus());
+        }
+
+        // 更新状态
+        applicationForWithdrawalChannelMapper.updateById(applicationForWithdrawalChannelDO);
+
+        Long allCount = applicationForWithdrawalChannelMapper.selectCount(ApplicationForWithdrawalChannelDO::getPtDailyWithdrawalId, applicationForWithdrawalChannelDO.getPtDailyWithdrawalId());
+        Long successCount = applicationForWithdrawalChannelMapper.selectCount(PtSettlemntStatusEnum.SETTLEMENT.getStatus(),applicationForWithdrawalChannelDO.getPtDailyWithdrawalId());
+
+        PtDailyWithdrawalDO ptDailyWithdrawal = ptDailyWithdrawalService.getPtDailyWithdrawal(applicationForWithdrawalChannelDO.getPtDailyWithdrawalId());
+
+        // 更新一级记录的提现状态
+        if(allCount.equals(successCount)){
+            ptDailyWithdrawal.setStatus(PtSettlemntStatusEnum.SETTLEMENT.getStatus());
+        }else if(successCount == 0) {
+            ptDailyWithdrawal.setStatus(PtSettlemntStatusEnum.SETTLEMENT_SUCCESS.getStatus());
+        }else {
+            ptDailyWithdrawal.setStatus(PtSettlemntStatusEnum.SETTLEMENT_ERROR.getStatus());
+        }
+
+        // 更新状态
+        ptDailyWithdrawalService.updatePtDailyWithdrawal(BeanUtils.toBean(ptDailyWithdrawal, PtDailyWithdrawalSaveReqVO.class));
+
+        return errorList;
+
+    }
+
 }

+ 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);
 }

+ 389 - 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.ShopSettlementDO;
+import cn.newfeifan.mall.module.distri.dal.dataobject.shopsettlement.data.ShopSettlementErrorData;
+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,358 @@ 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<ShopSettlementDO> 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());
+
+            if(document.getNumberOfPages() == 0){
+                ErrorCode ERROR = new ErrorCode(1_002_030_028, "选择的文件是空的");
+                throw exception(ERROR);
+            }
+
+            // 创建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 (ShopSettlementDO shopSettlement : shopSettList) {
+                        // 判断日期是否同样
+                        isSameDate(shopSettlement, formatter, time);
+                    }
+                }
+
+                for (ShopSettlementDO shopSettlement : shopSettList) {
+                    // 账号
+                    String accountNumber = getErrorAccountNumber(pageText, false);
+                    // 户名
+                    String accountName = getErrorAccountName(pageText, false);
+                    // 金额
+                    String money = getMoney(pageText);
+
+                    if (shopSettlement.getAccountNumber().equals(accountNumber) &&
+                            shopSettlement.getAccountName().equals(accountName) &&
+                            shopSettlement.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(shopSettlement, ShopSettlementSaveReqVO.class);
+                        bean.setAttachment(fileUrl);
+
+                        // 保存修改结算单
+                        shopSettlementService.updateShopSettlement(bean);
+                    }
+                }
+            }
+
+            // 回退错误的回执单导致的结算单信息
+            if (!errorList.isEmpty()) {
+
+                for (ShopSettlementErrorData shopSettlementErrorData : errorList) {
+
+                    for (ShopSettlementDO shopSettlement : shopSettList) {
+
+                        if (shopSettlement.getAccountNumber().equals(shopSettlementErrorData.getAccountNumber()) &&
+                                shopSettlement.getAccountName().equals(shopSettlementErrorData.getAccountName()) &&
+                                shopSettlement.getShopTotalHighAmount().divide(new BigDecimal("100"), 2, RoundingMode.FLOOR).toString().equals(shopSettlementErrorData.getMoney())
+                        ) {
+                            ShopSettlementSaveReqVO bean = BeanUtils.toBean(shopSettlement, ShopSettlementSaveReqVO.class);
+                            bean.setAttachment(null);
+
+                            shopSettlementErrorData.setShopSettlement(BeanUtils.toBean(bean, ShopSettlementRespVO.class));
+
+                            shopSettlementService.updateShopSettlement(bean);
+                        }
+                    }
+                }
+            }
+
+            boolean status = true;
+            for (ShopSettlementDO shopSettlement : shopSettList) {
+                if (shopSettlement.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) {
+            String message = e.getMessage();
+            if(e.getMessage().equals("String index out of range: -1")){
+                message = "上传的PDF文件内容不正确!";
+            }
+
+            ErrorCode ERROR = new ErrorCode(1_002_030_027, "处理PDF文件异常: " + message);
+            throw exception(ERROR);
+        }
+
+        return errorList;
+    }
+
+    /**
+     * 判断备注的账单日期是否与结算单为同一天
+     *
+     * @param shopSettlement 结算单
+     * @param formatter             日期格式
+     * @param time                  日期
+     */
+    private void isSameDate(ShopSettlementDO shopSettlement, DateTimeFormatter formatter, String time) {
+        // 使用定义的格式器格式化LocalDateTime对象
+        String formattedDate = shopSettlement.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;
+    }
+
+
 }

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

@@ -66,4 +66,12 @@ public interface ShopSettlementService {
      * 结算已确权订单(也是按照每个店铺)
      */
     void settlementOrder();
+
+
+    /**
+     * 根据平台id查询
+     * @param id ptID
+     * @return 店铺结算信息
+     */
+    List<ShopSettlementDO> selectListByPtId(Long id);
 }

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

@@ -130,7 +130,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());
         }
@@ -167,6 +167,8 @@ public class ShopSettlementServiceImpl implements ShopSettlementService {
 
         for (MerchantDTO merchant : merchantDTOS) {
             for (Long shopId : merchant.getShopIds()) {
+                // 后面补加的,记录结算时的账号,而不是实时的
+                ShopDTO shop = shopApi.getShop(shopId);
                 List<OrderDTO> orders = shopSettlementMapper.getOrderByMerchantIdWithsShopId(shopId, merchant.getMerchantId());
                 // 当前店铺没有订单,则跳过
                 if (orders.isEmpty()) {
@@ -232,6 +234,8 @@ public class ShopSettlementServiceImpl implements ShopSettlementService {
                         .platformCollectionAmount(platformCollectionAmount)
                         .shopAmount(payIntegral)
                         .shopTotalHighAmount(totalHighAmount.setScale(6, RoundingMode.HALF_UP))
+                        .accountName(shop.getAccountName())
+                        .accountNumber(shop.getAccountNumber())
                         .build();
                 shopSettlementDOS.add(shopSett);
             }
@@ -273,4 +277,9 @@ public class ShopSettlementServiceImpl implements ShopSettlementService {
         });
 
     }
+
+    @Override
+    public List<ShopSettlementDO> selectListByPtId(Long id) {
+        return shopSettlementMapper.selectList(ShopSettlementDO::getPtSettlementId, id);
+    }
 }

+ 1 - 0
feifan-module-system/feifan-module-system-api/src/main/java/cn/newfeifan/mall/module/system/enums/sms/SmsSceneEnum.java

@@ -20,6 +20,7 @@ public enum SmsSceneEnum implements IntArrayValuable {
     MEMBER_UPDATE_MOBILE(2, "user-update-mobile", "会员用户 - 修改手机"),
     MEMBER_UPDATE_PASSWORD(3, "user-update-password", "会员用户 - 修改密码"),
     MEMBER_RESET_PASSWORD(4, "user-reset-password", "会员用户 - 忘记密码"),
+    MEMBER_WITHDRAWAL_ERROR(6, "user-withdrawal-error", "会员用户 - 提现失败时发送通知给用户"),
 
     ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录");
 

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

@@ -28,7 +28,7 @@ CREATE TABLE `distri_application_for_withdrawal_channel` (
                                                              `withdrawal_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '提现渠道名称',
                                                              `amount` bigint NOT NULL DEFAULT '0' COMMENT '提现金额,单位:元',
                                                              `count` int NOT NULL DEFAULT '0' COMMENT '提现笔数',
-                                                             `status` bit(1) DEFAULT b'0' COMMENT '提现状态,已完成是1,未完成为0',
+                                                             `status` tinyint DEFAULT '0' COMMENT '提现状态, 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败',
                                                              `pt_daily_withdrawal_id` bigint NOT NULL COMMENT '提现渠道记录id',
                                                              `excel_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '导出状态,已导出是1,未导出为0',
                                                              `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '' COMMENT '创建者',
@@ -43,7 +43,7 @@ CREATE TABLE `distri_pt_daily_withdrawal` (
                                               `id` bigint NOT NULL AUTO_INCREMENT COMMENT '记录id',
                                               `amount` bigint NOT NULL DEFAULT '0' COMMENT '提现金额,单位:元',
                                               `count` int NOT NULL DEFAULT '0' COMMENT '提现笔数',
-                                              `status` tinyint DEFAULT '0' COMMENT '提现状态,0:待转账 1:全部完成 2:部分完成',
+                                              `status` tinyint DEFAULT '0' COMMENT '提现状态, 0:未完成 , 1:已完成 , 2:部分完成 , 3:全部失败',
                                               `start_time` datetime NOT NULL COMMENT '提现开始时间',
                                               `end_time` datetime NOT NULL COMMENT '提现截止时间',
                                               `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '' COMMENT '创建者',
@@ -52,9 +52,19 @@ CREATE TABLE `distri_pt_daily_withdrawal` (
                                               `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
                                               `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
                                               PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='平台每日提现记录表';
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='平台每日提现记录表';
 
 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:全部失败';
+
+AlTER TABLE trade_shop_settlement
+    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 '账户号码';
+
+ALTER TABLE trade_pt_settlement
+    ADD COLUMN   `export_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '导出状态,已导出是1,未导出为0';