소스 검색

对账单

24282 1 년 전
부모
커밋
075bb2ea88
59개의 변경된 파일3986개의 추가작업 그리고 4개의 파일을 삭제
  1. 71 0
      sd-business/src/main/java/com/sd/business/controller/excel/ExcelGenerateLogController.java
  2. 103 0
      sd-business/src/main/java/com/sd/business/controller/statement/StatementOfAccountController.java
  3. 155 0
      sd-business/src/main/java/com/sd/business/controller/statement/StatementOfAccountMergeController.java
  4. 17 0
      sd-business/src/main/java/com/sd/business/entity/excel/dto/ExcelGenerateLogDto.java
  5. 19 0
      sd-business/src/main/java/com/sd/business/entity/excel/dto/ExcelGenerateLogSelectDto.java
  6. 21 0
      sd-business/src/main/java/com/sd/business/entity/excel/enums/ExcelStatusEnum.java
  7. 43 0
      sd-business/src/main/java/com/sd/business/entity/excel/enums/ExcelTypeEnum.java
  8. 48 0
      sd-business/src/main/java/com/sd/business/entity/excel/po/ExcelGenerateLog.java
  9. 17 0
      sd-business/src/main/java/com/sd/business/entity/excel/vo/ExcelGenerateLogVo.java
  10. 52 0
      sd-business/src/main/java/com/sd/business/entity/sku/bom/SkuSpecBo.java
  11. 141 0
      sd-business/src/main/java/com/sd/business/entity/statement/bo/ExportDocumentByOrderBo.java
  12. 18 0
      sd-business/src/main/java/com/sd/business/entity/statement/dto/DocumentInfoSelectDto.java
  13. 38 0
      sd-business/src/main/java/com/sd/business/entity/statement/dto/ExportDocumentDto.java
  14. 23 0
      sd-business/src/main/java/com/sd/business/entity/statement/dto/FileUploadDto.java
  15. 23 0
      sd-business/src/main/java/com/sd/business/entity/statement/dto/GetDocumentDto.java
  16. 36 0
      sd-business/src/main/java/com/sd/business/entity/statement/dto/SalesOutWarehouseDetailsDto.java
  17. 33 0
      sd-business/src/main/java/com/sd/business/entity/statement/dto/SalesRevenueCostSelectDto.java
  18. 1 1
      sd-business/src/main/java/com/sd/business/entity/statement/dto/StatementOfAccountDto.java
  19. 24 0
      sd-business/src/main/java/com/sd/business/entity/statement/dto/StatementOfAccountMergePageDto.java
  20. 17 1
      sd-business/src/main/java/com/sd/business/entity/statement/dto/StatementOfAccountSelectDto.java
  21. 1 1
      sd-business/src/main/java/com/sd/business/entity/statement/po/StatementOfAccount.java
  22. 49 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/DeliveryOfGoodsVO.java
  23. 79 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentByBomVo.java
  24. 191 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentByOrderVo.java
  25. 202 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentByRevenueCostVo.java
  26. 59 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentBySkuVo.java
  27. 73 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/ReconciliationDetailVo.java
  28. 52 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/StatementOfAccountMergePageVo.java
  29. 30 1
      sd-business/src/main/java/com/sd/business/entity/statement/vo/StatementOfAccountVo.java
  30. 40 0
      sd-business/src/main/java/com/sd/business/entity/statement/vo/StatementOrderClassifyTotalCountVo.java
  31. 16 0
      sd-business/src/main/java/com/sd/business/mapper/excel/ExcelGenerateLogMapper.java
  32. 5 0
      sd-business/src/main/java/com/sd/business/mapper/order/OrderInfoMapper.java
  33. 50 0
      sd-business/src/main/java/com/sd/business/service/excel/ExcelGenerateLogService.java
  34. 182 0
      sd-business/src/main/java/com/sd/business/service/excel/impl/ExcelGenerateLogServiceImpl.java
  35. 5 0
      sd-business/src/main/java/com/sd/business/service/inventory/InventoryFinishedOrderService.java
  36. 9 0
      sd-business/src/main/java/com/sd/business/service/inventory/impl/InventoryFinishedOrderServiceImpl.java
  37. 6 0
      sd-business/src/main/java/com/sd/business/service/order/OrderInfoService.java
  38. 10 0
      sd-business/src/main/java/com/sd/business/service/order/impl/OrderInfoServiceImpl.java
  39. 5 0
      sd-business/src/main/java/com/sd/business/service/sku/SkuSpecService.java
  40. 25 0
      sd-business/src/main/java/com/sd/business/service/sku/impl/SkuSpecServiceImpl.java
  41. 17 0
      sd-business/src/main/java/com/sd/business/service/statement/StatementOfAccountExportService.java
  42. 97 0
      sd-business/src/main/java/com/sd/business/service/statement/StatementOfAccountMergeService.java
  43. 57 0
      sd-business/src/main/java/com/sd/business/service/statement/StatementOfAccountService.java
  44. 100 0
      sd-business/src/main/java/com/sd/business/service/statement/impl/DocumentByOrderExcelCellMergeStrategy.java
  45. 100 0
      sd-business/src/main/java/com/sd/business/service/statement/impl/SalesOutWarehouseDetailsExcelCellMergeStrategy.java
  46. 62 0
      sd-business/src/main/java/com/sd/business/service/statement/impl/StatementOfAccountExportServiceImpl.java
  47. 690 0
      sd-business/src/main/java/com/sd/business/service/statement/impl/StatementOfAccountMergeServiceImpl.java
  48. 471 0
      sd-business/src/main/java/com/sd/business/service/statement/impl/StatementOfAccountServiceImpl.java
  49. 11 0
      sd-business/src/main/java/com/sd/business/strategy/ExcelExportStrategy.java
  50. 46 0
      sd-business/src/main/java/com/sd/business/strategy/impl/DefaultExportStrategy.java
  51. 155 0
      sd-business/src/main/java/com/sd/business/strategy/impl/DocumentByOrderExcelExportStrategy.java
  52. 154 0
      sd-business/src/main/java/com/sd/business/strategy/impl/SalesOutWarehouseDetailsExportStrategy.java
  53. 21 0
      sd-business/src/main/java/com/sd/business/util/StreamUtil.java
  54. 5 0
      sd-business/src/main/resources/mapper/excel/ExcelGenerateLogMapper.xml
  55. 11 0
      sd-business/src/main/resources/mapper/order/OrderInfoMapper.xml
  56. BIN
      sd-starter/src/main/resources/template/bomDocument.xlsx
  57. BIN
      sd-starter/src/main/resources/template/orderDocument.xlsx
  58. BIN
      sd-starter/src/main/resources/template/salesOutWarehouseDetails.xlsx
  59. BIN
      sd-starter/src/main/resources/template/skuDocument.xlsx

+ 71 - 0
sd-business/src/main/java/com/sd/business/controller/excel/ExcelGenerateLogController.java

@@ -0,0 +1,71 @@
+package com.sd.business.controller.excel;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.domain.BaseSelectDto;
+import com.sd.business.entity.excel.dto.ExcelGenerateLogDto;
+import com.sd.business.entity.excel.dto.ExcelGenerateLogSelectDto;
+import com.sd.business.entity.excel.vo.ExcelGenerateLogVo;
+import com.sd.business.service.excel.ExcelGenerateLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+
+/**
+ * <p>
+ * excel生成记录 前端控制器
+ * </p>
+ *
+ * @author
+ * @since 2024-01-17
+ */
+@RestController
+@RequestMapping("/excelGenerateLog")
+public class ExcelGenerateLogController {
+
+    @Autowired
+    private ExcelGenerateLogService excelGenerateLogService;
+
+    /**
+     * excel生成记录分页
+     */
+    @PostMapping("/page")
+    public Page<ExcelGenerateLogVo> page(@RequestBody ExcelGenerateLogSelectDto dto) {
+        return excelGenerateLogService.getPage(dto);
+    }
+
+    /**
+     * excel生成记录明细
+     */
+    @PostMapping("/detail")
+    public ExcelGenerateLogVo detail(@RequestBody BaseSelectDto dto) {
+        return excelGenerateLogService.detail(dto.getId());
+    }
+
+    /**
+     * excel生成记录新增
+     */
+    @PostMapping("/add")
+    public void add(@RequestBody ExcelGenerateLogDto dto) {
+        excelGenerateLogService.add(dto);
+    }
+
+    /**
+     * excel生成记录编辑
+     */
+    @PostMapping("/edit")
+    public void edit(@RequestBody ExcelGenerateLogDto dto) {
+        excelGenerateLogService.edit(dto);
+    }
+
+    /**
+     * excel生成记录删除
+     */
+    @PostMapping("/delete")
+    public void delete(@RequestBody BaseSelectDto dto) {
+        excelGenerateLogService.delete(dto.getId());
+    }
+
+}

+ 103 - 0
sd-business/src/main/java/com/sd/business/controller/statement/StatementOfAccountController.java

@@ -1,17 +1,28 @@
 package com.sd.business.controller.statement;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.annotation.NonInterception;
 import com.ruoyi.common.core.domain.BaseSelectDto;
+import com.sd.business.entity.statement.dto.DocumentInfoSelectDto;
+import com.sd.business.entity.statement.dto.FileUploadDto;
 import com.sd.business.entity.statement.dto.StatementOfAccountDto;
 import com.sd.business.entity.statement.dto.StatementOfAccountSelectDto;
+import com.sd.business.entity.statement.vo.DocumentByBomVo;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.entity.statement.vo.DocumentBySkuVo;
 import com.sd.business.entity.statement.vo.StatementOfAccountVo;
+import com.sd.business.entity.statement.vo.StatementOrderClassifyTotalCountVo;
 import com.sd.business.service.statement.StatementOfAccountService;
 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.RestController;
 
+import java.util.Collections;
+import java.util.List;
+
 
 /**
  * <p>
@@ -68,4 +79,96 @@ public class StatementOfAccountController {
         statementOfAccountService.delete(dto.getId());
     }
 
+
+    /**
+     * 编辑对账单文件
+     */
+    @PostMapping("/editReceiptFile")
+    public void editReceiptFile(@RequestBody FileUploadDto dto) {
+        statementOfAccountService.editFile(dto, 1);
+    }
+
+    /**
+     * 编辑转账凭证文件
+     */
+    @PostMapping("/editProofFile")
+    public void editProofFile(@RequestBody FileUploadDto dto) {
+        statementOfAccountService.editFile(dto, 2);
+    }
+
+    /**
+     * sku对账
+     */
+    @PostMapping("/getDocumentBySku")
+    public List<DocumentBySkuVo> getDocumentBySku(@RequestBody DocumentInfoSelectDto dto) {
+        return statementOfAccountService.getSkuDocument(Collections.singletonList(dto.getId()), dto.getOrderClassify());
+    }
+
+    /**
+     * bom对账
+     */
+    @PostMapping("/getDocumentByBom")
+    public List<DocumentByBomVo> getDocumentByBom(@RequestBody DocumentInfoSelectDto dto) {
+        return statementOfAccountService.getBomDocument(Collections.singletonList(dto.getId()), dto.getOrderClassify());
+    }
+
+    /**
+     * 订单对账
+     */
+    @PostMapping("/getDocumentByOrder")
+    public List<DocumentByOrderVo> getDocumentByOrder(@RequestBody DocumentInfoSelectDto dto) {
+        return statementOfAccountService.getOrderDocument(Collections.singletonList(dto.getId()), dto.getOrderClassify());
+    }
+
+    /**
+     * 导出sku对账单
+     */
+    @NonInterception
+    @GetMapping("/exportDocumentBySku")
+    public void exportDocumentBySku(DocumentInfoSelectDto dto) {
+        statementOfAccountService.export(dto.getId(), dto.getOrderClassify(), 1);
+    }
+
+    /**
+     * 导出bom对账单
+     */
+    @NonInterception
+    @GetMapping("/exportDocumentByBom")
+    public void exportDocumentByBom(DocumentInfoSelectDto dto) {
+        statementOfAccountService.export(dto.getId(), dto.getOrderClassify(), 2);
+    }
+
+    /**
+     * 导出订单对账单
+     */
+    @GetMapping("/exportDocumentByOrder")
+    public void exportDocumentByOrder(DocumentInfoSelectDto dto) {
+        statementOfAccountService.export(dto.getId(), dto.getOrderClassify(), 3);
+    }
+
+    /**
+     * 获取万里牛单号
+     */
+    @PostMapping("/getOrderWlnCodeStr")
+    public String getOrderWlnCodeStr(@RequestBody List<Long> idList) {
+        return statementOfAccountService.getOrderWlnCodeStr(idList);
+    }
+
+    /**
+     * 获取对账单订单分类总计
+     */
+    @PostMapping("/getOrderClassifyTotalCount")
+    public StatementOrderClassifyTotalCountVo getOrderClassifyTotalCount(@RequestBody List<Long> idList) {
+        return statementOfAccountService.getOrderClassifyTotalCount(idList);
+    }
+
+    /**
+     * 获取对账单未签核的数量
+     */
+    @PostMapping("/getNotCheckCount")
+    public Long getNotCheckCount() {
+        return statementOfAccountService.getNotCheckCount();
+    }
+
+
 }

+ 155 - 0
sd-business/src/main/java/com/sd/business/controller/statement/StatementOfAccountMergeController.java

@@ -0,0 +1,155 @@
+package com.sd.business.controller.statement;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.annotation.NonInterception;
+import com.sd.business.entity.statement.dto.ExportDocumentDto;
+import com.sd.business.entity.statement.dto.GetDocumentDto;
+import com.sd.business.entity.statement.dto.SalesOutWarehouseDetailsDto;
+import com.sd.business.entity.statement.dto.SalesRevenueCostSelectDto;
+import com.sd.business.entity.statement.dto.StatementOfAccountMergePageDto;
+import com.sd.business.entity.statement.vo.DocumentByBomVo;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.entity.statement.vo.DocumentByRevenueCostVo;
+import com.sd.business.entity.statement.vo.DocumentBySkuVo;
+import com.sd.business.entity.statement.vo.StatementOfAccountMergePageVo;
+import com.sd.business.service.statement.StatementOfAccountMergeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+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.RestController;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 对账单 前端控制器
+ * </p>
+ *
+ * @author
+ * @since 2023-07-31
+ */
+@RestController
+@RequestMapping("/statementOfAccountMerge")
+public class StatementOfAccountMergeController {
+
+    @Autowired
+    private StatementOfAccountMergeService statementOfAccountMergeService;
+
+    /**
+     * 对账报表分页
+     */
+    @PostMapping("/page")
+    public Page<StatementOfAccountMergePageVo> page(@Validated @RequestBody StatementOfAccountMergePageDto dto) {
+        return statementOfAccountMergeService.getPage(dto);
+    }
+
+    /**
+     * sku对账
+     */
+    @PostMapping("/getDocumentBySku")
+    public List<DocumentBySkuVo> getDocumentBySku(@RequestBody GetDocumentDto dto) {
+        return statementOfAccountMergeService.getDocumentBySku(dto);
+    }
+
+    /**
+     * bom对账
+     */
+    @PostMapping("/getDocumentByBom")
+    public List<DocumentByBomVo> getDocumentByBom(@RequestBody GetDocumentDto dto) {
+        return statementOfAccountMergeService.getDocumentByBom(dto);
+    }
+
+    /**
+     * 订单对账
+     */
+    @PostMapping("/getDocumentByOrder")
+    public List<DocumentByOrderVo> getDocumentByOrder(@RequestBody GetDocumentDto dto) {
+        return statementOfAccountMergeService.getDocumentByOrder(dto);
+    }
+
+    /**
+     * 导出sku对账单
+     */
+    @NonInterception
+    @GetMapping("/exportDocumentBySku")
+    public void exportDocumentBySku(@Validated ExportDocumentDto dto) {
+        statementOfAccountMergeService.export(dto, 1);
+    }
+
+    /**
+     * 导出bom对账单
+     */
+    @NonInterception
+    @GetMapping("/exportDocumentByBom")
+    public void exportDocumentByBom(@Validated ExportDocumentDto dto) {
+        statementOfAccountMergeService.export(dto, 2);
+    }
+
+    /**
+     * 导出订单对账单
+     */
+    @GetMapping("/exportDocumentByOrder")
+    public void exportDocumentByOrder(@Validated ExportDocumentDto dto) {
+        statementOfAccountMergeService.export(dto, 3);
+    }
+
+    /**
+     * 销售出货明细
+     */
+    @PostMapping("/salesOutWarehouseDetails")
+    public Page<DocumentByOrderVo> salesOutWarehouseDetails(@RequestBody SalesOutWarehouseDetailsDto dto) {
+        return statementOfAccountMergeService.salesOutWarehouseDetails(dto);
+    }
+
+    /**
+     * 销售出货明细
+     */
+    @PostMapping("/exportSalesOutWarehouseDetails")
+    public void exportSalesOutWarehouseDetails(@RequestBody SalesOutWarehouseDetailsDto dto) {
+        statementOfAccountMergeService.exportSalesOutWarehouseDetails(dto);
+    }
+
+    /**
+     * 销售出货明细
+     */
+    @PostMapping("/salesRevenueCostPage")
+    public Page<DocumentByRevenueCostVo> salesRevenueCostPage(@RequestBody SalesRevenueCostSelectDto dto) {
+        return statementOfAccountMergeService.salesRevenueCostPage(dto);
+    }
+
+    /**
+     * 销售出货明细
+     */
+    @PostMapping("/exportSalesRevenueCostData")
+    public void exportSalesRevenueCostData(@RequestBody SalesRevenueCostSelectDto dto) {
+        statementOfAccountMergeService.exportSalesRevenueCostData(dto);
+    }
+
+    /**
+     * 货物交接单
+     */
+    @PostMapping("/exportDeliveryOfGoodsExcel")
+    public void exportExcel(@RequestBody List<Long> idList) {
+        statementOfAccountMergeService.exportDeliveryOfGoodsExcel(idList);
+    }
+
+    /**
+     * 获取无理由订单没有销货出库的订单列表
+     */
+    @PostMapping("/getNotSalesOutOfWarehouseOrder")
+    public List<Long> getNotSalesOutOfWarehouseOrder(@RequestBody GetDocumentDto dto) {
+        return statementOfAccountMergeService.getNotSalesOutOfWarehouseOrder(dto);
+    }
+
+    /**
+     * 无理由订单成品出库
+     */
+    @PostMapping("/salesOutOfWarehouse")
+    public void salesOutOfWarehouse(@RequestBody List<Long> idList) {
+        statementOfAccountMergeService.salesOutOfWarehouseByOrderIds(idList);
+    }
+}

+ 17 - 0
sd-business/src/main/java/com/sd/business/entity/excel/dto/ExcelGenerateLogDto.java

@@ -0,0 +1,17 @@
+package com.sd.business.entity.excel.dto;
+
+import com.sd.business.entity.excel.po.ExcelGenerateLog;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * excel生成记录新增编辑入参实体
+ *
+ * @author
+ * @since 2024-01-17
+ */
+@Getter
+@Setter
+public class ExcelGenerateLogDto extends ExcelGenerateLog {
+
+}

+ 19 - 0
sd-business/src/main/java/com/sd/business/entity/excel/dto/ExcelGenerateLogSelectDto.java

@@ -0,0 +1,19 @@
+package com.sd.business.entity.excel.dto;
+
+import com.ruoyi.common.core.domain.BaseSelectDto;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * excel生成记录列表查询入参实体
+ *
+ * @author
+ * @since 2024-01-17
+ */
+@Getter
+@Setter
+public class ExcelGenerateLogSelectDto extends BaseSelectDto {
+
+    private Integer type;
+
+}

+ 21 - 0
sd-business/src/main/java/com/sd/business/entity/excel/enums/ExcelStatusEnum.java

@@ -0,0 +1,21 @@
+package com.sd.business.entity.excel.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum ExcelStatusEnum {
+
+    PROCESSING_DATA(1, "数据处理中"),
+    GENERATE(2, "excel生成中"),
+    UPLOAD(3, "excel上传中"),
+    COMPLETE(4, "完成"),
+
+    FAIL(99, "excel生成失败");
+
+
+    private final Integer status;
+    private final String explain;
+
+}

+ 43 - 0
sd-business/src/main/java/com/sd/business/entity/excel/enums/ExcelTypeEnum.java

@@ -0,0 +1,43 @@
+package com.sd.business.entity.excel.enums;
+
+import com.ruoyi.common.exception.ServiceException;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+@AllArgsConstructor
+public enum ExcelTypeEnum {
+
+    DOCUMENT_BY_ORDER(1, "订单对账单"),
+    STATISTICS_DOCUMENT_BY_ORDER(2, "订单对账报表"),
+    PURCHASE_WAREHOUSING(3, "采购入库明细"),
+    SALES_OUT_WAREHOUSE_DETAILS(4, "销货出库明细"),
+    DOCUMENT_BY_SALES_REVENUE_COST(5, "销售收入成本表"),
+    ;
+
+    private static final Map<Integer, ExcelTypeEnum> map = new HashMap<>();
+
+    static {
+        for (ExcelTypeEnum excelTypeEnum : values()) {
+            map.put(excelTypeEnum.getType(), excelTypeEnum);
+        }
+    }
+
+    private final Integer type;
+    private final String explain;
+
+    /**
+     * 通过key获取名称
+     */
+    public static ExcelTypeEnum get(Integer key) {
+        ExcelTypeEnum excelTypeEnum = map.get(key);
+        if (excelTypeEnum == null) {
+            throw new ServiceException("未知导出状态:" + key);
+        }
+        return excelTypeEnum;
+    }
+
+}

+ 48 - 0
sd-business/src/main/java/com/sd/business/entity/excel/po/ExcelGenerateLog.java

@@ -0,0 +1,48 @@
+package com.sd.business.entity.excel.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.BasePo;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * excel生成记录
+ * </p>
+ *
+ * @author
+ * @since 2024-01-17
+ */
+@Getter
+@Setter
+@TableName("excel_generate_log")
+public class ExcelGenerateLog extends BasePo {
+
+    /**
+     * 业务类型
+     */
+    private Integer type;
+
+    /**
+     * 状态 1数据处理中 2excel生成中 3excel上传obs中 4完成
+     */
+    private Integer status;
+
+    /**
+     * excel文件路径
+     */
+    private String obsFileUrl;
+
+    /**
+     * excel文件名称
+     */
+    private String excelName;
+
+    /**
+     * 完成时间
+     */
+    private Date completionTime;
+
+}

+ 17 - 0
sd-business/src/main/java/com/sd/business/entity/excel/vo/ExcelGenerateLogVo.java

@@ -0,0 +1,17 @@
+package com.sd.business.entity.excel.vo;
+
+import com.sd.business.entity.excel.po.ExcelGenerateLog;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * excel生成记录列表查询返回值实体
+ *
+ * @author
+ * @since 2024-01-17
+ */
+@Getter
+@Setter
+public class ExcelGenerateLogVo extends ExcelGenerateLog {
+
+}

+ 52 - 0
sd-business/src/main/java/com/sd/business/entity/sku/bom/SkuSpecBo.java

@@ -0,0 +1,52 @@
+package com.sd.business.entity.sku.bom;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+public class SkuSpecBo {
+
+    /**
+     * sku规格id
+     */
+    private Long id;
+
+    /**
+     * 长 cm
+     */
+    private BigDecimal length;
+
+    /**
+     * 宽 cm
+     */
+    private BigDecimal width;
+
+    /**
+     * 高 cm
+     */
+    private BigDecimal height;
+
+    /**
+     * 净重 g
+     */
+    private BigDecimal netWeight;
+
+    /**
+     * sku规格编码
+     */
+    private String skuSpecCode;
+
+    /**
+     * sku规格名称
+     */
+    private String skuSpecName;
+
+    /**
+     * 分类名称
+     */
+    private String skuClassifyName;
+
+}

+ 141 - 0
sd-business/src/main/java/com/sd/business/entity/statement/bo/ExportDocumentByOrderBo.java

@@ -0,0 +1,141 @@
+package com.sd.business.entity.statement.bo;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Getter
+@Setter
+@Builder
+public class ExportDocumentByOrderBo {
+
+    /**
+     * 店铺名称
+     */
+    private String shopName;
+
+    /**
+     * 事业部名称
+     */
+    private String departmentName;
+
+    /**
+     * 对账时间
+     */
+    private Date statementOfAccountTime;
+
+    /**
+     * 定制加工类型
+     */
+    private String customProcessingType;
+
+    /**
+     * 分类父名称
+     */
+    private String classifyName;
+
+    /**
+     * 单位
+     */
+    private String unit;
+
+
+    /**
+     * 万里牛订单创建时间
+     */
+    private Date wlnCreateTime;
+
+    /**
+     * 订单号
+     */
+    private String code;
+
+    /**
+     * mes单号
+     */
+    private String mesCode;
+
+    /**
+     * 万里牛订单号
+     */
+    private String wlnCode;
+
+    /**
+     * 占位符
+     */
+    private Integer placeholder;
+
+    /**
+     * sku规格品号
+     */
+    private String skuSpecCode;
+
+    /**
+     * sku规格品名
+     */
+    private String skuSpecName;
+
+    /**
+     * 数量
+     */
+    private BigDecimal quantity;
+
+    /**
+     * sku单价
+     */
+    private BigDecimal unitPrice;
+
+    /**
+     * 小计
+     */
+    private BigDecimal subtotal;
+
+    /**
+     * 合计
+     */
+    private BigDecimal total;
+
+    /**
+     * bom规格品号
+     */
+    private String bomSpecCode;
+
+    /**
+     * bom规格品名
+     */
+    private String bomSpecName;
+
+    /**
+     * 数量
+     */
+    private BigDecimal bomQuantity;
+
+    /**
+     * bom单价
+     */
+    private BigDecimal bomUnitPrice;
+
+    /**
+     * 代发费
+     */
+    private BigDecimal lssueFeeSummary;
+
+    /**
+     * 快递包材费
+     */
+    private BigDecimal deliveryMaterialsFeeSummary;
+
+    /**
+     * 包装人工费
+     */
+    private BigDecimal packingLaborSummary;
+
+    /**
+     * 管理费
+     */
+    private BigDecimal managementFeeSummary;
+
+}

+ 18 - 0
sd-business/src/main/java/com/sd/business/entity/statement/dto/DocumentInfoSelectDto.java

@@ -0,0 +1,18 @@
+package com.sd.business.entity.statement.dto;
+
+import com.ruoyi.common.core.domain.BaseSelectDto;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 对账单详情查询入参实体
+ */
+@Getter
+@Setter
+public class DocumentInfoSelectDto extends BaseSelectDto {
+
+    /**
+     * 对账单订单分类 1-万里牛订单,2-采购订单,3-委外订单,4-售后订单,5-无理由订单
+     */
+    private Integer orderClassify;
+}

+ 38 - 0
sd-business/src/main/java/com/sd/business/entity/statement/dto/ExportDocumentDto.java

@@ -0,0 +1,38 @@
+package com.sd.business.entity.statement.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+@Getter
+@Setter
+public class ExportDocumentDto {
+
+    /**
+     * 对账单id集合
+     */
+    @NotBlank(message = "对账单id集合不能为空")
+    private String idGroupConcat;
+
+    /**
+     * 部门名称
+     */
+    private String departmentName;
+
+    /**
+     * 开始时间
+     */
+    private String beginDate;
+
+    /**
+     * 结束时间
+     */
+    private String endDate;
+
+    /**
+     * 订单分类 1-万里牛订单,2-采购订单,3-委外订单,4-售后订单,5-无理由订单
+     */
+    private Integer orderClassify;
+
+}

+ 23 - 0
sd-business/src/main/java/com/sd/business/entity/statement/dto/FileUploadDto.java

@@ -0,0 +1,23 @@
+package com.sd.business.entity.statement.dto;
+
+import com.fjhx.file.entity.ObsFile;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class FileUploadDto {
+
+    /**
+     * 对账单id
+     */
+    private Long id;
+
+    /**
+     * 文件列表
+     */
+    private List<ObsFile> fileList;
+
+}

+ 23 - 0
sd-business/src/main/java/com/sd/business/entity/statement/dto/GetDocumentDto.java

@@ -0,0 +1,23 @@
+package com.sd.business.entity.statement.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+@Getter
+@Setter
+public class GetDocumentDto {
+
+    /**
+     * 对账单id集合
+     */
+    @NotBlank(message = "对账单id集合不能为空")
+    private String idGroupConcat;
+
+    /**
+     * 对账单订单分类 1-万里牛订单,2-采购订单,3-委外订单,4-售后订单,5-无理由订单
+     */
+    private Integer orderClassify;
+
+}

+ 36 - 0
sd-business/src/main/java/com/sd/business/entity/statement/dto/SalesOutWarehouseDetailsDto.java

@@ -0,0 +1,36 @@
+package com.sd.business.entity.statement.dto;
+
+import com.ruoyi.common.core.domain.BaseSelectDto;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class SalesOutWarehouseDetailsDto extends BaseSelectDto {
+
+    /**
+     * 订单号
+     */
+    private String code;
+
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+    /**
+     * sku编码
+     */
+    private String skuSpecCode;
+
+    /**
+     * sku名称
+     */
+    private String skuSpecName;
+
+    /**
+     * 是否查询总条数
+     */
+    private Boolean searchCount = true;
+
+}

+ 33 - 0
sd-business/src/main/java/com/sd/business/entity/statement/dto/SalesRevenueCostSelectDto.java

@@ -0,0 +1,33 @@
+package com.sd.business.entity.statement.dto;
+
+import com.ruoyi.common.core.domain.BaseSelectDto;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 销售收入成本查询入参实体
+ */
+@Getter
+@Setter
+public class SalesRevenueCostSelectDto extends BaseSelectDto {
+
+    /**
+     * 订单号
+     */
+    private String code;
+
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+    /**
+     * sku编码
+     */
+    private String skuSpecCode;
+
+    /**
+     * sku名称
+     */
+    private String skuSpecName;
+}

+ 1 - 1
sd-business/src/main/java/com/sd/business/entity/statement/dto/StatementOfAccountDto.java

@@ -11,7 +11,7 @@ import java.util.List;
  * 对账单新增编辑入参实体
  *
  * @author
- * @since 2023-12-11
+ * @since 2023-07-31
  */
 @Getter
 @Setter

+ 24 - 0
sd-business/src/main/java/com/sd/business/entity/statement/dto/StatementOfAccountMergePageDto.java

@@ -0,0 +1,24 @@
+package com.sd.business.entity.statement.dto;
+
+import com.ruoyi.common.core.domain.BaseSelectDto;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+@Getter
+@Setter
+public class StatementOfAccountMergePageDto extends BaseSelectDto {
+
+    /**
+     * 对账类型(1月度 2季度 3年度 4自定义)
+     */
+    @NotNull(message = "对账类型不能为空")
+    private Integer type;
+
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+}

+ 17 - 1
sd-business/src/main/java/com/sd/business/entity/statement/dto/StatementOfAccountSelectDto.java

@@ -8,10 +8,26 @@ import lombok.Setter;
  * 对账单列表查询入参实体
  *
  * @author
- * @since 2023-12-11
+ * @since 2023-07-31
  */
 @Getter
 @Setter
 public class StatementOfAccountSelectDto extends BaseSelectDto {
 
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+    /**
+     * 对账单号
+     */
+    private String code;
+
+    /**
+     * 核对状态 1 已核对,0 未核对
+     */
+    private Integer checkStatus;
+
+
 }

+ 1 - 1
sd-business/src/main/java/com/sd/business/entity/statement/po/StatementOfAccount.java

@@ -43,6 +43,6 @@ public class StatementOfAccount extends BasePo {
     /**
      * 核对状态 1 已核对,0 未核对
      */
-    private Boolean checkStatus;
+    private Integer checkStatus;
 
 }

+ 49 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/DeliveryOfGoodsVO.java

@@ -0,0 +1,49 @@
+package com.sd.business.entity.statement.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Getter
+@Setter
+@ExcelIgnoreUnannotated
+public class DeliveryOfGoodsVO {
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "出入库单号")
+    private String receiptNumber;
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "业务日期")
+    private Date businessDate;
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "仓库")
+    private String warehouse;
+
+    @ColumnWidth(30)
+    @ExcelProperty(value = "规格")
+    private String spec;
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "出库数量")
+    private BigDecimal outboundQuantity;
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "订单号")
+    private String orderCode;
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "系统订单号")
+    private String orderWlnCode;
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "快递单号")
+    private String express;
+
+}

+ 79 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentByBomVo.java

@@ -0,0 +1,79 @@
+package com.sd.business.entity.statement.vo;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+@Builder
+public class DocumentByBomVo {
+
+    /**
+     * bom规格id
+     */
+    private Long bomSpecId;
+
+    /**
+     * bom品号
+     */
+    private String bomSpecCode;
+
+    /**
+     * bom品名
+     */
+    private String bomSpecName;
+
+    /**
+     * 数量
+     */
+    private BigDecimal quantity;
+
+    /**
+     * bom单价
+     */
+    private BigDecimal unitPrice;
+
+
+    /**
+     * 代发费汇总
+     */
+    private BigDecimal lssueFeeSummary;
+
+    /**
+     * 快递包材费汇总
+     */
+    private BigDecimal deliveryMaterialsFeeSummary;
+
+    /**
+     * 包装人工费汇总
+     */
+    private BigDecimal packingLaborSummary;
+
+    /**
+     * 管理费汇总
+     */
+    private BigDecimal managementFeeSummary;
+
+    /**
+     * 小计
+     */
+    private BigDecimal subtotal;
+
+    /**
+     * 合计
+     */
+    private BigDecimal total;
+
+    /**
+     * 占位符
+     */
+    private Integer placeholder;
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+}

+ 191 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentByOrderVo.java

@@ -0,0 +1,191 @@
+package com.sd.business.entity.statement.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Getter
+@Setter
+public class DocumentByOrderVo {
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+    /**
+     * 万里牛订单创建时间
+     */
+    private Date wlnCreateTime;
+
+    /**
+     * 订单号
+     */
+    private String code;
+
+    /**
+     * 万里牛订单号
+     */
+    private String wlnCode;
+
+    /**
+     * 占位符
+     */
+    private Integer placeholder;
+
+    /**
+     * 合计
+     */
+    private BigDecimal total;
+
+    /**
+     * 店铺来源
+     */
+    private String sourcePlatform;
+
+    /**
+     * 店铺名称
+     */
+    private String shopName;
+
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+    /**
+     * 事业部名称
+     */
+    private String departmentName;
+
+    /**
+     * 对账单id
+     */
+    private Long statementOfAccountId;
+
+    /**
+     * 对账时间
+     */
+    private Date statementOfAccountTime;
+
+    /**
+     * sku规格列表
+     */
+    private List<SkuSpec> skuSpecList;
+
+    @Getter
+    @Setter
+    public static class SkuSpec {
+
+        /**
+         * 订单id
+         */
+        private Long orderId;
+
+        /**
+         * 订单sku id
+         */
+        private Long orderSkuId;
+
+        /**
+         * sku规格id
+         */
+        private Long skuSpecId;
+
+        /**
+         * sku规格品号
+         */
+        private String skuSpecCode;
+
+        /**
+         * sku规格品名
+         */
+        private String skuSpecName;
+
+        /**
+         * 数量
+         */
+        private BigDecimal quantity;
+
+        /**
+         * sku单价
+         */
+        private BigDecimal unitPrice;
+
+        /**
+         * 小计
+         */
+        private BigDecimal subtotal;
+
+        /**
+         * bom规格列表
+         */
+        private List<BomSpec> bomSpecList;
+
+    }
+
+    @Getter
+    @Setter
+    public static class BomSpec {
+
+        /**
+         * 订单sku id
+         */
+        private Long orderSkuId;
+
+        /**
+         * bom规格id
+         */
+        private Long bomSpecId;
+
+        /**
+         * bom规格品号
+         */
+        private String bomSpecCode;
+
+        /**
+         * bom规格品名
+         */
+        private String bomSpecName;
+
+        /**
+         * 数量
+         */
+        private BigDecimal quantity;
+
+        /**
+         * bom单价
+         */
+        private BigDecimal unitPrice;
+
+        /**
+         * 代发费
+         */
+        private BigDecimal lssueFeeSummary;
+
+        /**
+         * 快递包材费
+         */
+        private BigDecimal deliveryMaterialsFeeSummary;
+
+        /**
+         * 包装人工费
+         */
+        private BigDecimal packingLaborSummary;
+
+        /**
+         * 管理费
+         */
+        private BigDecimal managementFeeSummary;
+
+        /**
+         * 分类父名称
+         */
+        private String classifyName;
+
+    }
+
+}

+ 202 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentByRevenueCostVo.java

@@ -0,0 +1,202 @@
+package com.sd.business.entity.statement.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.HeadFontStyle;
+import com.alibaba.excel.annotation.write.style.HeadRowHeight;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 收入成本列表查询返回值实体
+ *
+ * @author
+ * @since 2023-10-11
+ */
+@Getter
+@Setter
+@Builder
+@ExcelIgnoreUnannotated
+@HeadRowHeight(35)
+@HeadFontStyle(fontHeightInPoints = 10)
+public class DocumentByRevenueCostVo {
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+    /**
+     * 对账单id
+     */
+    private Long statementOfAccountId;
+
+    /**
+     * 序号
+     */
+    @ExcelProperty({"销售收入成本表", "序号"})
+    private Integer serialNumber;
+
+    /**
+     * 发货时间
+     */
+    @ColumnWidth(20)
+    @ExcelProperty({"销售收入成本表", "销售日期"})
+    private Date salesDate;
+
+    /**
+     * 客户编号
+     */
+    @ExcelProperty({"销售收入成本表", "客户编号"})
+    private String customerCode;
+
+    /**
+     * 客户名称
+     */
+    @ExcelProperty({"销售收入成本表", "客户名称"})
+    private String customerName;
+
+    /**
+     * 事业部名称
+     */
+    @ExcelProperty({"销售收入成本表", "事业部"})
+    private String departmentName;
+
+    /**
+     * 销售订单号
+     */
+    @ColumnWidth(20)
+    @ExcelProperty({"销售收入成本表", "销售订单号"})
+    private String code;
+
+    /**
+     * 万里牛单号
+     */
+    @ColumnWidth(20)
+    @ExcelProperty({"销售收入成本表", "万里牛单号"})
+    private String wlnCode;
+
+    /**
+     * 出库单号
+     */
+    @ExcelProperty({"销售收入成本表", "出库单号"})
+    private String outStorageCode;
+
+    /**
+     * sku规格品号
+     */
+    @ExcelProperty({"销售收入成本表", "成品品号"})
+    private String skuSpecCode;
+
+    /**
+     * sku规格品名
+     */
+    @ExcelProperty({"销售收入成本表", "成品名称"})
+    private String skuSpecName;
+
+    /**
+     * 规格
+     */
+    @ExcelProperty({"销售收入成本表", "规格"})
+    private String spec;
+
+    /**
+     * 成品类别
+     */
+    @ExcelProperty({"销售收入成本表", "成品类别"})
+    private String classifyName;
+
+    /**
+     * 计量单位
+     */
+    @ExcelProperty({"销售收入成本表", "计量单位"})
+    private String measuringUnit;
+
+    /**
+     * 销售数量
+     */
+    @ExcelProperty({"销售收入成本表", "销售数量"})
+    private BigDecimal quantity;
+
+    /**
+     * 销售单价
+     */
+    @ExcelProperty({"销售收入成本表", "销售单价"})
+    private BigDecimal salesUnitPrice;
+
+    /**
+     * 销售金额
+     */
+    @ExcelProperty({"销售收入成本表", "销售金额"})
+    private BigDecimal salesAmount;
+
+    /**
+     * 产品金额
+     */
+    @ExcelProperty({"销售收入成本表", "其中:产品金额"})
+    private BigDecimal productAmount;
+
+    /**
+     * 代发金额
+     */
+    @ExcelProperty({"销售收入成本表", "其中:代发金额"})
+    private BigDecimal issuingAmount;
+
+    /**
+     * 其他金额(包装人工费)
+     */
+    @ExcelProperty({"销售收入成本表", "其中:其他金额"})
+    private BigDecimal otherAmount;
+
+    /**
+     * 材料成本
+     */
+    @ExcelProperty({"销售收入成本表", "材料成本"})
+    private BigDecimal materialCost;
+
+    /**
+     * 辅料成本
+     */
+    @ExcelProperty({"销售收入成本表", "辅料成本"})
+    private BigDecimal auxiliaryMaterialCost;
+
+    /**
+     * 产品包材成本
+     */
+    @ExcelProperty({"销售收入成本表", "产品包材成本"})
+    private BigDecimal productPackagingMaterialCost;
+
+    /**
+     * 物流包材成本
+     */
+    @ExcelProperty({"销售收入成本表", "物流包材成本"})
+    private BigDecimal logisticsPackagingMaterialCost;
+
+    /**
+     * 成本小计
+     */
+    @ExcelProperty({"销售收入成本表", "成本小计"})
+    private BigDecimal costSubtotal;
+
+    /**
+     * 毛利
+     */
+    @ExcelProperty({"销售收入成本表", "毛利"})
+    private BigDecimal grossProfit;
+
+    /**
+     * 毛利率
+     */
+    @ExcelProperty({"销售收入成本表", "毛利率"})
+    private String grossProfitRate;
+}

+ 59 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/DocumentBySkuVo.java

@@ -0,0 +1,59 @@
+package com.sd.business.entity.statement.vo;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+@Builder
+public class DocumentBySkuVo {
+
+    /**
+     * sku规格id
+     */
+    private Long skuSpecId;
+
+    /**
+     * sku品号
+     */
+    private String skuSpecCode;
+
+    /**
+     * sku品名
+     */
+    private String skuSpecName;
+
+    /**
+     * 数量
+     */
+    private BigDecimal quantity;
+
+    /**
+     * sku单价
+     */
+    private BigDecimal unitPrice;
+
+    /**
+     * 小计
+     */
+    private BigDecimal subtotal;
+
+    /**
+     * 合计
+     */
+    private BigDecimal total;
+
+    /**
+     * 占位符
+     */
+    private Integer placeholder;
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+}

+ 73 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/ReconciliationDetailVo.java

@@ -0,0 +1,73 @@
+package com.sd.business.entity.statement.vo;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+@Builder
+public class ReconciliationDetailVo {
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+    /**
+     * 事业部名称
+     */
+    private String departmentName;
+
+    /**
+     * 订单号
+     */
+    private String orderCode;
+
+    /**
+     * 订单总金额
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 产品总金额
+     */
+    private BigDecimal productTotalAmount;
+
+    /**
+     * 定制加工费
+     */
+    private BigDecimal customProcessingFee;
+
+    /**
+     * 代发费
+     */
+    private BigDecimal lssueFee;
+
+    /**
+     * 快递包材费
+     */
+    private BigDecimal deliveryMaterialsFee;
+
+    /**
+     * 包装人工费
+     */
+    private BigDecimal packingLabor;
+
+    /**
+     * 包材费
+     */
+    private BigDecimal packagingMaterialCost;
+
+    /**
+     * 管理费
+     */
+    private BigDecimal managementFee;
+}

+ 52 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/StatementOfAccountMergePageVo.java

@@ -0,0 +1,52 @@
+package com.sd.business.entity.statement.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+public class StatementOfAccountMergePageVo {
+
+    /**
+     * 维度
+     */
+    private String dimensionality;
+
+    /**
+     * 事业部id
+     */
+    private Long departmentId;
+
+    /**
+     * 事业部名称
+     */
+    private String departmentName;
+
+    /**
+     * 对账单id集合
+     */
+    private String idGroupConcat;
+
+    /**
+     * 对账金额
+     */
+    private BigDecimal reconcilingAmount;
+
+    /**
+     * 对账单数量
+     */
+    private Integer quantityOfStatement;
+
+    /**
+     * 合同数量
+     */
+    private Integer orderQuantity;
+
+    /**
+     * 核对状态 1 已核对,0 未核对
+     */
+    private Integer checkStatus;
+
+}

+ 30 - 1
sd-business/src/main/java/com/sd/business/entity/statement/vo/StatementOfAccountVo.java

@@ -1,17 +1,46 @@
 package com.sd.business.entity.statement.vo;
 
+import com.fjhx.file.entity.FileInfoVo;
 import com.sd.business.entity.statement.po.StatementOfAccount;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.math.BigDecimal;
+import java.util.List;
+
 /**
  * 对账单列表查询返回值实体
  *
  * @author
- * @since 2023-12-11
+ * @since 2023-07-31
  */
 @Getter
 @Setter
 public class StatementOfAccountVo extends StatementOfAccount {
 
+    /**
+     * 事业部名称
+     */
+    private String departmentName;
+
+    /**
+     * 对账金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 订单数量
+     */
+    private int orderNum;
+
+    /**
+     * 对账单
+     */
+    private List<FileInfoVo> receiptFileList;
+
+    /**
+     * 转正凭证
+     */
+    private List<FileInfoVo> proofFileList;
+
 }

+ 40 - 0
sd-business/src/main/java/com/sd/business/entity/statement/vo/StatementOrderClassifyTotalCountVo.java

@@ -0,0 +1,40 @@
+package com.sd.business.entity.statement.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 对账单订单分类数量总计查询返回值实体
+ *
+ * @author
+ * @since 2023-10-17
+ */
+@Getter
+@Setter
+public class StatementOrderClassifyTotalCountVo {
+
+    /**
+     * 万里牛订单数量
+     */
+    private Integer wlnOrderCount;
+
+    /**
+     * 采购订单数量
+     */
+    private Integer purchaseOrderCount;
+
+    /**
+     * 委外订单数量
+     */
+    private Integer outsourceOrderCount;
+
+    /**
+     * 售后订单数量
+     */
+    private Integer afterSaleOrderCount;
+
+    /**
+     * 无理由订单数量
+     */
+    private Integer noReasonOrderCount;
+}

+ 16 - 0
sd-business/src/main/java/com/sd/business/mapper/excel/ExcelGenerateLogMapper.java

@@ -0,0 +1,16 @@
+package com.sd.business.mapper.excel;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.sd.business.entity.excel.po.ExcelGenerateLog;
+
+/**
+ * <p>
+ * excel生成记录 Mapper 接口
+ * </p>
+ *
+ * @author
+ * @since 2024-01-17
+ */
+public interface ExcelGenerateLogMapper extends BaseMapper<ExcelGenerateLog> {
+
+}

+ 5 - 0
sd-business/src/main/java/com/sd/business/mapper/order/OrderInfoMapper.java

@@ -1,7 +1,10 @@
 package com.sd.business.mapper.order;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.common.utils.wrapper.IWrapper;
 import com.sd.business.entity.order.po.OrderInfo;
+import com.sd.business.entity.statement.vo.StatementOrderClassifyTotalCountVo;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * <p>
@@ -13,4 +16,6 @@ import com.sd.business.entity.order.po.OrderInfo;
  */
 public interface OrderInfoMapper extends BaseMapper<OrderInfo> {
 
+    StatementOrderClassifyTotalCountVo getOrderClassifyTotalCount(@Param("ew") IWrapper<OrderInfo> wrapper);
+
 }

+ 50 - 0
sd-business/src/main/java/com/sd/business/service/excel/ExcelGenerateLogService.java

@@ -0,0 +1,50 @@
+package com.sd.business.service.excel;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.service.BaseService;
+import com.sd.business.entity.excel.dto.ExcelGenerateLogDto;
+import com.sd.business.entity.excel.dto.ExcelGenerateLogSelectDto;
+import com.sd.business.entity.excel.enums.ExcelTypeEnum;
+import com.sd.business.entity.excel.po.ExcelGenerateLog;
+import com.sd.business.entity.excel.vo.ExcelGenerateLogVo;
+import com.sd.business.strategy.ExcelExportStrategy;
+
+
+/**
+ * <p>
+ * excel生成记录 服务类
+ * </p>
+ *
+ * @author
+ * @since 2024-01-17
+ */
+public interface ExcelGenerateLogService extends BaseService<ExcelGenerateLog> {
+
+    /**
+     * excel生成记录分页
+     */
+    Page<ExcelGenerateLogVo> getPage(ExcelGenerateLogSelectDto dto);
+
+    /**
+     * excel生成记录明细
+     */
+    ExcelGenerateLogVo detail(Long id);
+
+    /**
+     * excel生成记录新增
+     */
+    void add(ExcelGenerateLogDto dto);
+
+    /**
+     * excel生成记录编辑
+     */
+    void edit(ExcelGenerateLogDto dto);
+
+    /**
+     * excel生成记录删除
+     */
+    void delete(Long id);
+
+    <T> Long generateExcel(ExcelTypeEnum excelTypeEnum, ExcelExportStrategy<T> exportStrategy, String fileName);
+
+}

+ 182 - 0
sd-business/src/main/java/com/sd/business/service/excel/impl/ExcelGenerateLogServiceImpl.java

@@ -0,0 +1,182 @@
+package com.sd.business.service.excel.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.obs.services.ObsClient;
+import com.ruoyi.common.core.domain.BaseIdPo;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.sd.business.entity.excel.dto.ExcelGenerateLogDto;
+import com.sd.business.entity.excel.dto.ExcelGenerateLogSelectDto;
+import com.sd.business.entity.excel.enums.ExcelStatusEnum;
+import com.sd.business.entity.excel.enums.ExcelTypeEnum;
+import com.sd.business.entity.excel.po.ExcelGenerateLog;
+import com.sd.business.entity.excel.vo.ExcelGenerateLogVo;
+import com.sd.business.mapper.excel.ExcelGenerateLogMapper;
+import com.sd.business.service.excel.ExcelGenerateLogService;
+import com.sd.business.strategy.ExcelExportStrategy;
+import com.sd.framework.util.Assert;
+import com.sd.framework.util.sql.Sql;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.InputStream;
+import java.util.Date;
+import java.util.StringJoiner;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * <p>
+ * excel生成记录 服务实现类
+ * </p>
+ *
+ * @author
+ * @since 2024-01-17
+ */
+@Service
+public class ExcelGenerateLogServiceImpl extends ServiceImpl<ExcelGenerateLogMapper, ExcelGenerateLog> implements ExcelGenerateLogService {
+
+    private static final ThreadPoolExecutor excelExecutor = new ThreadPoolExecutor(
+            3,
+            6,
+            60,
+            TimeUnit.SECONDS,
+            new LinkedBlockingQueue<>(6),
+            Executors.defaultThreadFactory(),
+            (Runnable runnable, ThreadPoolExecutor executor) -> {
+                throw new ServiceException("当前系统导出excel数量过多,系统负载过大,请稍后重试");
+            }
+    );
+
+
+    @Value("${obs.ak}")
+    private String ak;
+
+    @Value("${obs.sk}")
+    private String sk;
+
+    @Value("${obs.endPoint}")
+    private String endPoint;
+
+    @Value("${obs.url}")
+    private String url;
+
+    @Value("${obs.bucketName}")
+    private String bucketName;
+
+    @Value("${spring.profiles.active}")
+    private String active;
+
+    @Value("${ruoyi.name}")
+    private String name;
+
+
+    @Override
+    public Page<ExcelGenerateLogVo> getPage(ExcelGenerateLogSelectDto dto) {
+
+        return Sql.create(ExcelGenerateLogVo.class)
+                .selectAll(ExcelGenerateLog.class)
+                .from(ExcelGenerateLog.class)
+                .orderByDesc(ExcelGenerateLog::getId)
+                .eq(ExcelGenerateLog::getCreateUser, SecurityUtils.getUserId())
+                .eq(ExcelGenerateLog::getType, dto.getType())
+                .page(dto);
+
+    }
+
+    @Override
+    public ExcelGenerateLogVo detail(Long id) {
+
+        ExcelGenerateLogVo vo = Sql.create(ExcelGenerateLogVo.class)
+                .selectAll(ExcelGenerateLog.class)
+                .from(ExcelGenerateLog.class)
+                .eq(ExcelGenerateLog::getId, id)
+                .one();
+
+        Assert.notNull(vo, "未知数据");
+
+        return vo;
+    }
+
+    @Override
+    public void add(ExcelGenerateLogDto dto) {
+        save(dto);
+    }
+
+    @Override
+    public void edit(ExcelGenerateLogDto dto) {
+        updateById(dto);
+    }
+
+    @Override
+    public void delete(Long id) {
+        removeById(id);
+    }
+
+    @Override
+    public <T> Long generateExcel(ExcelTypeEnum excelTypeEnum, ExcelExportStrategy<T> exportStrategy, String fileName) {
+
+        fileName = fileName + (fileName.endsWith(".xlsx") ? "" : fileName.endsWith(".xls?") ?
+                "x" : fileName.endsWith(".") ? "xlsx" : ".xlsx");
+
+        // 文件路径
+        String objectKey = new StringJoiner("/")
+                .add(name)
+                .add(active)
+                .add("excel")
+                .add(DateUtil.format(new Date(), "yyyy/MM/dd"))
+                .add(IdUtil.fastSimpleUUID())
+                .add(fileName)
+                .toString();
+
+        ExcelGenerateLog excelGenerateLog = new ExcelGenerateLog();
+        excelGenerateLog.setType(excelTypeEnum.getType());
+        excelGenerateLog.setStatus(ExcelStatusEnum.PROCESSING_DATA.getStatus());
+        excelGenerateLog.setExcelName(fileName);
+        excelGenerateLog.setObsFileUrl(url + objectKey);
+        save(excelGenerateLog);
+
+        Long id = excelGenerateLog.getId();
+
+        excelExecutor.execute(() -> {
+
+            DynamicDataSourceContextHolder.push("business");
+
+            try {
+                T data = exportStrategy.getData();
+                update(q -> q.eq(BaseIdPo::getId, id).set(ExcelGenerateLog::getStatus, ExcelStatusEnum.GENERATE.getStatus()));
+
+                InputStream inputStream = exportStrategy.getInputStream(data);
+                update(q -> q.eq(BaseIdPo::getId, id).set(ExcelGenerateLog::getStatus, ExcelStatusEnum.UPLOAD.getStatus()));
+
+                getObsClient().putObject(bucketName, objectKey, inputStream);
+                update(q -> q.eq(BaseIdPo::getId, id)
+                        .set(ExcelGenerateLog::getStatus, ExcelStatusEnum.COMPLETE.getStatus())
+                        .set(ExcelGenerateLog::getCompletionTime, new Date())
+                );
+            } catch (Exception e) {
+                log.error("导出失败", e);
+                update(q -> q.eq(BaseIdPo::getId, id)
+                        .set(ExcelGenerateLog::getStatus, ExcelStatusEnum.FAIL.getStatus())
+                        .set(ExcelGenerateLog::getCompletionTime, null));
+            } finally {
+                DynamicDataSourceContextHolder.poll();
+            }
+
+        });
+
+        return id;
+    }
+
+    private ObsClient getObsClient() {
+        return new ObsClient(ak, sk, endPoint);
+    }
+
+}

+ 5 - 0
sd-business/src/main/java/com/sd/business/service/inventory/InventoryFinishedOrderService.java

@@ -64,4 +64,9 @@ public interface InventoryFinishedOrderService extends BaseService<InventoryFini
      */
     void saleOutOfWarehouse(List<InventoryFinishedOrder> list);
 
+    /**
+     * 根据订单id列表查询没有销货出库的订单
+     */
+    List<Long> getNotSalesOutOfWarehouseOrderByIds(List<Long> orderIdList);
+
 }

+ 9 - 0
sd-business/src/main/java/com/sd/business/service/inventory/impl/InventoryFinishedOrderServiceImpl.java

@@ -318,4 +318,13 @@ public class InventoryFinishedOrderServiceImpl extends ServiceImpl<InventoryFini
         inventoryFinishedOrderDetailService.add(list, FinishedOperationTypeEnum.SALE_OUT_OF_WAREHOUSE);
     }
 
+    @Override
+    public List<Long> getNotSalesOutOfWarehouseOrderByIds(List<Long> orderIdList) {
+        List<InventoryFinishedOrder> list = this.list(q -> q.in(InventoryFinishedOrder::getOrderInfoId, orderIdList)
+                .eq(InventoryFinishedOrder::getStatus, StatusConstant.NO));
+        List<Long> notInInventoryOrderIds = list.stream().map(InventoryFinishedOrder::getOrderInfoId).collect(Collectors.toList());
+        orderIdList.removeAll(notInInventoryOrderIds);
+        return orderIdList;
+    }
+
 }

+ 6 - 0
sd-business/src/main/java/com/sd/business/service/order/OrderInfoService.java

@@ -11,6 +11,7 @@ import com.sd.business.entity.order.po.OrderInfo;
 import com.sd.business.entity.order.vo.OrderInfoVo;
 import com.sd.business.entity.order.vo.OrderPackageBomVo;
 import com.sd.business.entity.order.vo.SkuSpecPriceVo;
+import com.sd.business.entity.statement.vo.StatementOrderClassifyTotalCountVo;
 
 import java.util.List;
 
@@ -110,4 +111,9 @@ public interface OrderInfoService extends BaseService<OrderInfo> {
      */
     void orderExportExcel(Long id);
 
+    /**
+     * 获取对账单订单分类总计
+     */
+    StatementOrderClassifyTotalCountVo getOrderClassifyTotalCount(List<Long> idList);
+
 }

+ 10 - 0
sd-business/src/main/java/com/sd/business/service/order/impl/OrderInfoServiceImpl.java

@@ -16,6 +16,7 @@ import com.ruoyi.common.core.domain.BasePo;
 import com.ruoyi.common.core.domain.BaseSelectDto;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.wrapper.IWrapper;
 import com.ruoyi.system.service.ISysUserService;
 import com.sd.business.entity.bom.bo.BomSpecBo;
 import com.sd.business.entity.bom.po.Bom;
@@ -50,6 +51,7 @@ import com.sd.business.entity.price.po.PriceBillingStandard;
 import com.sd.business.entity.price.po.PriceBillingStandardDetail;
 import com.sd.business.entity.sku.po.SkuSpec;
 import com.sd.business.entity.sku.po.SkuSpecLink;
+import com.sd.business.entity.statement.vo.StatementOrderClassifyTotalCountVo;
 import com.sd.business.entity.warehouse.constant.WarehouseConstant;
 import com.sd.business.entity.work.constant.MaterialsConstant;
 import com.sd.business.entity.work.enums.WorkOrderFixationSpecEnum;
@@ -713,6 +715,14 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
         ExcelUtil.export(response, exportVoList, OrderSkuExportVo.class);
     }
 
+    @Override
+    public StatementOrderClassifyTotalCountVo getOrderClassifyTotalCount(List<Long> idList) {
+        Assert.notEmpty(idList, "对账单id不能为空");
+        IWrapper<OrderInfo> wrapper = getWrapper();
+        wrapper.in("o", OrderInfo::getStatementOfAccountId, idList);
+        return this.baseMapper.getOrderClassifyTotalCount(wrapper);
+    }
+
     /**
      * 订单修改快递包材出入库操作
      */

+ 5 - 0
sd-business/src/main/java/com/sd/business/service/sku/SkuSpecService.java

@@ -1,9 +1,12 @@
 package com.sd.business.service.sku;
 
 import com.ruoyi.common.core.service.BaseService;
+import com.sd.business.entity.sku.bom.SkuSpecBo;
 import com.sd.business.entity.sku.po.SkuSpec;
 
 import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -21,4 +24,6 @@ public interface SkuSpecService extends BaseService<SkuSpec> {
      */
     BigDecimal getSkuInventoryQuantity(Long id);
 
+    Map<Long, SkuSpecBo> getSkuSpecBoByIdList(List<Long> skuSpecIds);
+
 }

+ 25 - 0
sd-business/src/main/java/com/sd/business/service/sku/impl/SkuSpecServiceImpl.java

@@ -4,6 +4,9 @@ import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sd.business.entity.bom.bo.BomSpecBo;
 import com.sd.business.entity.inventory.po.Inventory;
+import com.sd.business.entity.sku.bom.SkuSpecBo;
+import com.sd.business.entity.sku.po.Sku;
+import com.sd.business.entity.sku.po.SkuClassify;
 import com.sd.business.entity.sku.po.SkuSpec;
 import com.sd.business.entity.warehouse.constant.WarehouseConstant;
 import com.sd.business.mapper.sku.SkuSpecMapper;
@@ -11,10 +14,14 @@ import com.sd.business.service.bom.BomSpecService;
 import com.sd.business.service.inventory.InventoryService;
 import com.sd.business.service.sku.SkuSpecService;
 import com.sd.framework.util.Assert;
+import com.sd.framework.util.sql.Sql;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -66,4 +73,22 @@ public class SkuSpecServiceImpl extends ServiceImpl<SkuSpecMapper, SkuSpec> impl
         return ObjectUtil.defaultIfNull(inventory.getQuantity(), BigDecimal.ZERO);
     }
 
+    @Override
+    public Map<Long, SkuSpecBo> getSkuSpecBoByIdList(List<Long> skuSpecIds) {
+        if (skuSpecIds.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        return Sql.create(SkuSpecBo.class)
+                .select(SkuSpec::getId, SkuSpec::getLength, SkuSpec::getWidth, SkuSpec::getHeight, SkuSpec::getNetWeight)
+                .selectAs(SkuSpec::getCode, SkuSpecBo::getSkuSpecCode)
+                .selectAs(SkuSpec::getName, SkuSpecBo::getSkuSpecName)
+                .selectAs(SkuClassify::getName, SkuSpecBo::getSkuClassifyName)
+                .from(SkuSpec.class)
+                .leftJoin(Sku.class, SkuSpec::getSkuId)
+                .leftJoin(SkuClassify.class, Sku::getSkuClassifyId)
+                .in(SkuSpec::getId, skuSpecIds)
+                .mapKEntity(SkuSpecBo::getId);
+    }
+
 }

+ 17 - 0
sd-business/src/main/java/com/sd/business/service/statement/StatementOfAccountExportService.java

@@ -0,0 +1,17 @@
+package com.sd.business.service.statement;
+
+import java.util.List;
+
+public interface StatementOfAccountExportService {
+
+    /**
+     * 导出sku对账单
+     */
+    void exportDocumentBySku(List<Long> idList, String departmentName, String beginDate, String endDate, Integer orderClassify);
+
+    /**
+     * 导出bom对账单
+     */
+    void exportDocumentByBom(List<Long> idList, String departmentName, String beginDate, String endDate, Integer orderClassify);
+
+}

+ 97 - 0
sd-business/src/main/java/com/sd/business/service/statement/StatementOfAccountMergeService.java

@@ -0,0 +1,97 @@
+package com.sd.business.service.statement;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.sd.business.entity.statement.dto.ExportDocumentDto;
+import com.sd.business.entity.statement.dto.GetDocumentDto;
+import com.sd.business.entity.statement.dto.SalesOutWarehouseDetailsDto;
+import com.sd.business.entity.statement.dto.SalesRevenueCostSelectDto;
+import com.sd.business.entity.statement.dto.StatementOfAccountMergePageDto;
+import com.sd.business.entity.statement.vo.DocumentByBomVo;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.entity.statement.vo.DocumentByRevenueCostVo;
+import com.sd.business.entity.statement.vo.DocumentBySkuVo;
+import com.sd.business.entity.statement.vo.StatementOfAccountMergePageVo;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 对账单 服务类
+ * </p>
+ *
+ * @author
+ * @since 2023-07-31
+ */
+public interface StatementOfAccountMergeService {
+
+    /**
+     * 对账报表分页
+     */
+    Page<StatementOfAccountMergePageVo> getPage(StatementOfAccountMergePageDto dto);
+
+    /**
+     * sku对账
+     */
+    List<DocumentBySkuVo> getDocumentBySku(GetDocumentDto dto);
+
+    /**
+     * bom对账
+     */
+    List<DocumentByBomVo> getDocumentByBom(GetDocumentDto dto);
+
+    /**
+     * 订单对账
+     */
+    List<DocumentByOrderVo> getDocumentByOrder(GetDocumentDto dto);
+
+    /**
+     * 导出
+     *
+     * @param dto  导出参数
+     * @param type 1sku 2bom 3订单
+     */
+    void export(ExportDocumentDto dto, int type);
+
+    /**
+     * 销售出货明细
+     */
+    Page<DocumentByOrderVo> salesOutWarehouseDetails(SalesOutWarehouseDetailsDto dto);
+
+    /**
+     * 导出销售出货明细
+     */
+    void exportSalesOutWarehouseDetails(SalesOutWarehouseDetailsDto dto);
+
+    /**
+     * 查询销售收入成本分页
+     *
+     * @param dto
+     * @return
+     */
+    Page<DocumentByRevenueCostVo> salesRevenueCostPage(SalesRevenueCostSelectDto dto);
+
+    /**
+     * 导出销售收入成本数据
+     *
+     * @param dto
+     */
+    void exportSalesRevenueCostData(SalesRevenueCostSelectDto dto);
+
+    /**
+     * 导出货物交接单excel
+     */
+    void exportDeliveryOfGoodsExcel(List<Long> idList);
+
+    /**
+     * 获取无理由订单没有销货出库的订单列表
+     *
+     * @param dto
+     * @return
+     */
+    List<Long> getNotSalesOutOfWarehouseOrder(GetDocumentDto dto);
+
+    /**
+     * 无理由订单成品出库
+     */
+    void salesOutOfWarehouseByOrderIds(List<Long> idList);
+}

+ 57 - 0
sd-business/src/main/java/com/sd/business/service/statement/StatementOfAccountService.java

@@ -2,10 +2,18 @@ package com.sd.business.service.statement;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.core.service.BaseService;
+import com.sd.business.entity.order.po.OrderInfo;
+import com.sd.business.entity.statement.dto.FileUploadDto;
 import com.sd.business.entity.statement.dto.StatementOfAccountDto;
 import com.sd.business.entity.statement.dto.StatementOfAccountSelectDto;
 import com.sd.business.entity.statement.po.StatementOfAccount;
+import com.sd.business.entity.statement.vo.DocumentByBomVo;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.entity.statement.vo.DocumentBySkuVo;
 import com.sd.business.entity.statement.vo.StatementOfAccountVo;
+import com.sd.business.entity.statement.vo.StatementOrderClassifyTotalCountVo;
+
+import java.util.List;
 
 
 /**
@@ -43,4 +51,53 @@ public interface StatementOfAccountService extends BaseService<StatementOfAccoun
      */
     void delete(Long id);
 
+    /**
+     * 更新文件
+     */
+    void editFile(FileUploadDto dto, int type);
+
+    /**
+     * sku对账
+     */
+    List<DocumentBySkuVo> getSkuDocument(List<Long> statementOfAccountId, Integer orderClassify);
+
+    /**
+     * bom对账
+     */
+    List<DocumentByBomVo> getBomDocument(List<Long> statementOfAccountId, Integer orderClassify);
+
+    /**
+     * 订单对账
+     */
+    List<DocumentByOrderVo> getOrderDocument(List<Long> statementOfAccountId, Integer orderClassify);
+
+    /**
+     * 订单对账
+     */
+    List<DocumentByOrderVo> getOrderDocumentByOrderList(List<OrderInfo> orderList);
+
+    /**
+     * 导出
+     *
+     * @param id            对账单id
+     * @param orderClassify 订单分类
+     * @param type          1sku 2bom 3订单
+     */
+    void export(Long id, Integer orderClassify, int type);
+
+    /**
+     * 获取万里牛单号
+     */
+    String getOrderWlnCodeStr(List<Long> idList);
+
+    /**
+     * 获取对账单订单分类总计
+     */
+    StatementOrderClassifyTotalCountVo getOrderClassifyTotalCount(List<Long> idList);
+
+    /**
+     * 获取未签核的数量
+     */
+    Long getNotCheckCount();
+
 }

+ 100 - 0
sd-business/src/main/java/com/sd/business/service/statement/impl/DocumentByOrderExcelCellMergeStrategy.java

@@ -0,0 +1,100 @@
+package com.sd.business.service.statement.impl;
+
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.write.merge.AbstractMergeStrategy;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class DocumentByOrderExcelCellMergeStrategy extends AbstractMergeStrategy {
+
+    // 最大行数
+    private final int maxRow;
+
+    // sku需要合并的列
+    private final List<Integer> skuColIndex = Arrays.asList(3, 4, 5, 16, 17);
+    // sku无需合并的行
+    private final List<Integer> skuRowIndex = new ArrayList<>();
+
+    // 订单需要合并的列
+    private final List<Integer> orderColIndex = Arrays.asList(0, 1, 2, 18);
+    // 订单无需合并的行
+    private final List<Integer> orderRowIndex = new ArrayList<>();
+
+    public DocumentByOrderExcelCellMergeStrategy(List<DocumentByOrderVo> documentByOrderVoList) {
+
+        // 无需合并的行数
+        int mergeRowIndex = 2;
+        skuRowIndex.add(mergeRowIndex);
+        orderRowIndex.add(mergeRowIndex);
+
+        for (DocumentByOrderVo documentByOrderVo : documentByOrderVoList) {
+            List<DocumentByOrderVo.SkuSpec> skuSpecList = documentByOrderVo.getSkuSpecList();
+
+            // 赋值订单无需合并的行
+            Integer size = skuSpecList.stream().map(item -> item.getBomSpecList().size()).reduce(0, Integer::sum);
+            int orderRowIndexNumber = orderRowIndex.isEmpty() ? mergeRowIndex : orderRowIndex.get(orderRowIndex.size() - 1);
+            orderRowIndex.add(size + orderRowIndexNumber);
+
+            // 赋值sku无需合并的行
+            for (DocumentByOrderVo.SkuSpec skuSpec : skuSpecList) {
+                int bomSpecListSize = skuSpec.getBomSpecList().size();
+                int skuRowIndexSize = skuRowIndex.size();
+                int skuRowIndexNumber = skuRowIndexSize == 0 ? mergeRowIndex : skuRowIndex.get(skuRowIndexSize - 1);
+                skuRowIndex.add(bomSpecListSize + skuRowIndexNumber);
+            }
+        }
+
+        maxRow = skuRowIndex.get(skuRowIndex.size() - 1);
+    }
+
+    @Override
+    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
+
+        // 当前行列
+        int curRowIndex = cell.getRowIndex();
+
+        // 判断是否是最后一行
+        if (curRowIndex != maxRow) {
+            return;
+        }
+
+        int curColIndex = cell.getColumnIndex();
+
+        // 合并订单列
+        if (orderColIndex.contains(curColIndex)) {
+            for (int i = 1; i < orderRowIndex.size(); i++) {
+                int beginRow = orderRowIndex.get(i - 1) + 1;
+                Integer endRow = orderRowIndex.get(i);
+                mergeWithPrevRow(sheet, beginRow, endRow, curColIndex);
+            }
+        }
+
+        // 合并sku列
+        else if (skuColIndex.contains(curColIndex)) {
+            for (int i = 1; i < skuRowIndex.size(); i++) {
+                int beginRow = skuRowIndex.get(i - 1) + 1;
+                Integer endRow = skuRowIndex.get(i);
+                mergeWithPrevRow(sheet, beginRow, endRow, curColIndex);
+            }
+        }
+
+    }
+
+    /**
+     * 合并单元格
+     */
+    private void mergeWithPrevRow(Sheet sheet, int beginRow, int endRow, int col) {
+        if (beginRow == endRow) {
+            return;
+        }
+        CellRangeAddress cellRangeAddress = new CellRangeAddress(beginRow, endRow, col, col);
+        sheet.addMergedRegionUnsafe(cellRangeAddress);
+    }
+
+}

+ 100 - 0
sd-business/src/main/java/com/sd/business/service/statement/impl/SalesOutWarehouseDetailsExcelCellMergeStrategy.java

@@ -0,0 +1,100 @@
+package com.sd.business.service.statement.impl;
+
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.write.merge.AbstractMergeStrategy;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class SalesOutWarehouseDetailsExcelCellMergeStrategy extends AbstractMergeStrategy {
+
+    // 最大行数
+    private final int maxRow;
+
+    // sku需要合并的列
+    private final List<Integer> skuColIndex = Arrays.asList(6, 7, 8, 22, 23);
+    // sku无需合并的行
+    private final List<Integer> skuRowIndex = new ArrayList<>();
+
+    // 订单需要合并的列
+    private final List<Integer> orderColIndex = Arrays.asList(0, 1, 2, 3, 4, 5, 24, 25);
+    // 订单无需合并的行
+    private final List<Integer> orderRowIndex = new ArrayList<>();
+
+    public SalesOutWarehouseDetailsExcelCellMergeStrategy(List<DocumentByOrderVo> documentByOrderVoList) {
+
+        // 无需合并的行数
+        int mergeRowIndex = 1;
+        skuRowIndex.add(mergeRowIndex);
+        orderRowIndex.add(mergeRowIndex);
+
+        for (DocumentByOrderVo documentByOrderVo : documentByOrderVoList) {
+            List<DocumentByOrderVo.SkuSpec> skuSpecList = documentByOrderVo.getSkuSpecList();
+
+            // 赋值订单无需合并的行
+            Integer size = skuSpecList.stream().map(item -> item.getBomSpecList().size()).reduce(0, Integer::sum);
+            int orderRowIndexNumber = orderRowIndex.isEmpty() ? mergeRowIndex : orderRowIndex.get(orderRowIndex.size() - 1);
+            orderRowIndex.add(size + orderRowIndexNumber);
+
+            // 赋值sku无需合并的行
+            for (DocumentByOrderVo.SkuSpec skuSpec : skuSpecList) {
+                int bomSpecListSize = skuSpec.getBomSpecList().size();
+                int skuRowIndexSize = skuRowIndex.size();
+                int skuRowIndexNumber = skuRowIndexSize == 0 ? mergeRowIndex : skuRowIndex.get(skuRowIndexSize - 1);
+                skuRowIndex.add(bomSpecListSize + skuRowIndexNumber);
+            }
+        }
+
+        maxRow = skuRowIndex.get(skuRowIndex.size() - 1);
+    }
+
+    @Override
+    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
+
+        // 当前行列
+        int curRowIndex = cell.getRowIndex();
+
+        // 判断是否是最后一行
+        if (curRowIndex != maxRow) {
+            return;
+        }
+
+        int curColIndex = cell.getColumnIndex();
+
+        // 合并订单列
+        if (orderColIndex.contains(curColIndex)) {
+            for (int i = 1; i < orderRowIndex.size(); i++) {
+                int beginRow = orderRowIndex.get(i - 1) + 1;
+                Integer endRow = orderRowIndex.get(i);
+                mergeWithPrevRow(sheet, beginRow, endRow, curColIndex);
+            }
+        }
+
+        // 合并sku列
+        else if (skuColIndex.contains(curColIndex)) {
+            for (int i = 1; i < skuRowIndex.size(); i++) {
+                int beginRow = skuRowIndex.get(i - 1) + 1;
+                Integer endRow = skuRowIndex.get(i);
+                mergeWithPrevRow(sheet, beginRow, endRow, curColIndex);
+            }
+        }
+
+    }
+
+    /**
+     * 合并单元格
+     */
+    private void mergeWithPrevRow(Sheet sheet, int beginRow, int endRow, int col) {
+        if (beginRow == endRow) {
+            return;
+        }
+        CellRangeAddress cellRangeAddress = new CellRangeAddress(beginRow, endRow, col, col);
+        sheet.addMergedRegionUnsafe(cellRangeAddress);
+    }
+
+}

+ 62 - 0
sd-business/src/main/java/com/sd/business/service/statement/impl/StatementOfAccountExportServiceImpl.java

@@ -0,0 +1,62 @@
+package com.sd.business.service.statement.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.sd.business.entity.order.enums.OrderClassifyEnum;
+import com.sd.business.entity.statement.vo.DocumentByBomVo;
+import com.sd.business.entity.statement.vo.DocumentBySkuVo;
+import com.sd.business.service.statement.StatementOfAccountExportService;
+import com.sd.business.service.statement.StatementOfAccountService;
+import com.sd.business.util.StreamUtil;
+import com.sd.framework.util.TemplateExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class StatementOfAccountExportServiceImpl implements StatementOfAccountExportService {
+
+    @Autowired
+    private HttpServletResponse response;
+
+    @Autowired
+    private StatementOfAccountService statementOfAccountService;
+
+    @Override
+    public void exportDocumentBySku(List<Long> idList, String departmentName, String beginDate, String endDate, Integer orderClassify) {
+
+        List<DocumentBySkuVo> list = statementOfAccountService.getSkuDocument(idList, orderClassify);
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("department", StrUtil.isBlank(departmentName) ? StringPool.EMPTY : departmentName + StringPool.DASH);
+        map.put("beginDate", beginDate);
+        map.put("endDate", endDate);
+        map.put("totalQuantity", StreamUtil.bigDecimalAdd(list, DocumentBySkuVo::getQuantity));
+        map.put("totalSubtotal", StreamUtil.bigDecimalAdd(list, DocumentBySkuVo::getSubtotal));
+
+        TemplateExcelUtil.writeBrowser("skuDocument.xlsx", OrderClassifyEnum.getEnum(orderClassify).getValue() + "-sku对账单", response, list, map);
+    }
+
+    @Override
+    public void exportDocumentByBom(List<Long> idList, String departmentName, String beginDate, String endDate, Integer orderClassify) {
+
+        List<DocumentByBomVo> list = statementOfAccountService.getBomDocument(idList, orderClassify);
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("department", StrUtil.isBlank(departmentName) ? StringPool.EMPTY : departmentName + StringPool.DASH);
+        map.put("beginDate", beginDate);
+        map.put("endDate", endDate);
+        map.put("totalSubtotal", StreamUtil.bigDecimalAdd(list, DocumentByBomVo::getSubtotal));
+        map.put("totalLssueFeeSummary", StreamUtil.bigDecimalAdd(list, DocumentByBomVo::getLssueFeeSummary));
+        map.put("totalDeliveryMaterialsFeeSummary", StreamUtil.bigDecimalAdd(list, DocumentByBomVo::getDeliveryMaterialsFeeSummary));
+        map.put("totalPackingLaborSummary", StreamUtil.bigDecimalAdd(list, DocumentByBomVo::getPackingLaborSummary));
+        map.put("totalManagementFeeSummary", StreamUtil.bigDecimalAdd(list, DocumentByBomVo::getManagementFeeSummary));
+
+        TemplateExcelUtil.writeBrowser("bomDocument.xlsx", OrderClassifyEnum.getEnum(orderClassify).getValue() + "-bom对账单", response, list, map);
+    }
+
+}

+ 690 - 0
sd-business/src/main/java/com/sd/business/service/statement/impl/StatementOfAccountMergeServiceImpl.java

@@ -0,0 +1,690 @@
+package com.sd.business.service.statement.impl;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.constant.StatusConstant;
+import com.ruoyi.common.core.domain.BaseIdPo;
+import com.ruoyi.common.core.domain.BasePo;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.PageUtils;
+import com.sd.business.entity.excel.enums.ExcelTypeEnum;
+import com.sd.business.entity.inventory.po.InventoryFinishedOrder;
+import com.sd.business.entity.inventory.po.InventoryFinishedOrderDetail;
+import com.sd.business.entity.order.enums.OrderClassifyEnum;
+import com.sd.business.entity.order.enums.OrderStatusEnum;
+import com.sd.business.entity.order.po.OrderInfo;
+import com.sd.business.entity.order.po.OrderSku;
+import com.sd.business.entity.order.po.OrderSkuProductionCost;
+import com.sd.business.entity.outbound.po.OutboundOrder;
+import com.sd.business.entity.sku.bom.SkuSpecBo;
+import com.sd.business.entity.sku.po.SkuSpec;
+import com.sd.business.entity.statement.dto.ExportDocumentDto;
+import com.sd.business.entity.statement.dto.GetDocumentDto;
+import com.sd.business.entity.statement.dto.SalesOutWarehouseDetailsDto;
+import com.sd.business.entity.statement.dto.SalesRevenueCostSelectDto;
+import com.sd.business.entity.statement.dto.StatementOfAccountMergePageDto;
+import com.sd.business.entity.statement.po.StatementOfAccount;
+import com.sd.business.entity.statement.vo.DeliveryOfGoodsVO;
+import com.sd.business.entity.statement.vo.DocumentByBomVo;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.entity.statement.vo.DocumentByRevenueCostVo;
+import com.sd.business.entity.statement.vo.DocumentBySkuVo;
+import com.sd.business.entity.statement.vo.StatementOfAccountMergePageVo;
+import com.sd.business.service.department.DepartmentService;
+import com.sd.business.service.excel.ExcelGenerateLogService;
+import com.sd.business.service.inventory.InventoryFinishedOrderDetailService;
+import com.sd.business.service.inventory.InventoryFinishedOrderService;
+import com.sd.business.service.inventory.InventoryFinishedService;
+import com.sd.business.service.order.OrderInfoService;
+import com.sd.business.service.order.OrderSkuProductionCostService;
+import com.sd.business.service.order.OrderSkuService;
+import com.sd.business.service.outbound.OutboundOrderService;
+import com.sd.business.service.sku.SkuSpecService;
+import com.sd.business.service.statement.StatementOfAccountExportService;
+import com.sd.business.service.statement.StatementOfAccountMergeService;
+import com.sd.business.service.statement.StatementOfAccountService;
+import com.sd.business.strategy.impl.DefaultExportStrategy;
+import com.sd.business.strategy.impl.DocumentByOrderExcelExportStrategy;
+import com.sd.business.strategy.impl.SalesOutWarehouseDetailsExportStrategy;
+import com.sd.framework.util.Assert;
+import com.sd.framework.util.excel.util.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletResponse;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 对账单 服务实现类
+ * </p>
+ *
+ * @author
+ * @since 2023-07-31
+ */
+@Service
+public class StatementOfAccountMergeServiceImpl implements StatementOfAccountMergeService {
+
+    @Autowired
+    private HttpServletResponse response;
+
+    @Autowired
+    private StatementOfAccountService statementOfAccountService;
+
+    @Autowired
+    private DepartmentService departmentService;
+
+    @Autowired
+    private OrderInfoService orderInfoService;
+
+    @Autowired
+    private StatementOfAccountExportService statementOfAccountExportService;
+
+    @Autowired
+    private ExcelGenerateLogService excelGenerateLogService;
+
+    @Autowired
+    private OrderSkuService orderSkuService;
+
+    @Autowired
+    private SkuSpecService skuSpecService;
+
+    @Autowired
+    private OrderSkuProductionCostService orderSkuProductionCostService;
+
+    @Autowired
+    private InventoryFinishedOrderDetailService inventoryFinishedOrderDetailService;
+
+    @Autowired
+    private InventoryFinishedService inventoryFinishedService;
+
+    @Autowired
+    private InventoryFinishedOrderService inventoryFinishedOrderService;
+
+    @Autowired
+    private OutboundOrderService outboundOrderService;
+
+    @Override
+    public Page<StatementOfAccountMergePageVo> getPage(StatementOfAccountMergePageDto dto) {
+
+        QueryWrapper<StatementOfAccount> wrapper = Wrappers.query();
+
+        wrapper.eq(ObjectUtil.isNotNull(dto.getDepartmentId()), "department_id", dto.getDepartmentId());
+        wrapper.groupBy("department_id");
+        wrapper.orderByDesc("dimensionality");
+
+        switch (dto.getType()) {
+            // 月度
+            case 1:
+                wrapper.select("department_id AS departmentId",
+                        "GROUP_CONCAT(id) AS idGroupConcat",
+                        "DATE_FORMAT(time_period,'%Y/%m月') AS dimensionality");
+                wrapper.groupBy("dimensionality");
+                break;
+
+            // 季度
+            case 2:
+                wrapper.select("department_id AS departmentId",
+                        "GROUP_CONCAT(id) AS idGroupConcat",
+                        "CONCAT(YEAR(time_period),'/第',QUARTER(time_period),'季度') AS dimensionality");
+                wrapper.groupBy("dimensionality");
+                break;
+
+            // 年度
+            case 3:
+                wrapper.select("department_id AS departmentId",
+                        "GROUP_CONCAT(id) AS idGroupConcat",
+                        "YEAR(time_period) AS dimensionality");
+                wrapper.groupBy("dimensionality");
+                break;
+
+            // 自定义
+            case 4:
+                String beginTime = dto.getBeginTime() == null ? StringPool.EMPTY : DateUtil.formatDate(dto.getBeginTime());
+                String endTime = dto.getEndTime() == null ? StringPool.EMPTY : DateUtil.formatDate(dto.getEndTime());
+
+                wrapper.select("department_id AS departmentId",
+                        "GROUP_CONCAT(id) AS idGroupConcat",
+                        "'" + beginTime + " - " + endTime + "' AS dimensionality");
+                wrapper.ge(ObjectUtil.isNotNull(dto.getBeginTime()), "time_period", dto.getBeginTime());
+                wrapper.le(ObjectUtil.isNotNull(dto.getEndTime()), "time_period", dto.getEndTime());
+                break;
+
+            default:
+                throw new ServiceException("未知对账类型");
+        }
+
+        Page<Map<String, Object>> mapPage = statementOfAccountService.pageMaps(dto.getPage(), wrapper);
+        Page<StatementOfAccountMergePageVo> page = PageUtils.copyPage(mapPage, StatementOfAccountMergePageVo.class);
+        List<StatementOfAccountMergePageVo> records = page.getRecords();
+        if (records.isEmpty()) {
+            return page;
+        }
+
+        departmentService.attributeAssign(records, StatementOfAccountMergePageVo::getDepartmentId,
+                (item, department) -> item.setDepartmentName(department.getName()));
+
+        // 对账单id列表
+        List<Long> statementOfAccountIdList = records.stream()
+                .map(StatementOfAccountMergePageVo::getIdGroupConcat)
+                .flatMap(item -> Arrays.stream(item.split(",")))
+                .map(Convert::toLong)
+                .distinct()
+                .collect(Collectors.toList());
+
+        Map<Long, List<OrderInfo>> map = orderInfoService.mapKGroup(OrderInfo::getStatementOfAccountId,
+                q -> q.in(OrderInfo::getStatementOfAccountId, statementOfAccountIdList));
+
+        Map<Long, Integer> statementOfAccountMap = statementOfAccountService.mapKV(BaseIdPo::getId, StatementOfAccount::getCheckStatus,
+                q -> q.in(BaseIdPo::getId, statementOfAccountIdList));
+
+        for (StatementOfAccountMergePageVo record : records) {
+
+            String[] tempStatementOfAccountIdList = record.getIdGroupConcat().split(",");
+
+            record.setReconcilingAmount(BigDecimal.ZERO);
+            record.setOrderQuantity(0);
+            record.setQuantityOfStatement(tempStatementOfAccountIdList.length);
+
+            for (String statementOfAccountIdStr : tempStatementOfAccountIdList) {
+                Long statementOfAccountId = Convert.toLong(statementOfAccountIdStr);
+                List<OrderInfo> tempOrderInfoList = map.get(statementOfAccountId);
+
+                if (ObjectUtil.isEmpty(tempOrderInfoList)) {
+                    continue;
+                }
+
+                BigDecimal reconcilingAmount = tempOrderInfoList.stream()
+                        .map(OrderInfo::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+
+                record.setOrderQuantity(record.getOrderQuantity() + tempOrderInfoList.size());
+                record.setReconcilingAmount(record.getReconcilingAmount().add(reconcilingAmount));
+
+                if (ObjectUtil.notEqual(record.getCheckStatus(), StatusConstant.NO)
+                        && ObjectUtil.equals(statementOfAccountMap.get(statementOfAccountId), StatusConstant.NO)) {
+                    record.setCheckStatus(StatusConstant.NO);
+                }
+            }
+
+        }
+
+        return page;
+    }
+
+    @Override
+    public List<DocumentBySkuVo> getDocumentBySku(GetDocumentDto dto) {
+        return statementOfAccountService.getSkuDocument(getIdList(dto), dto.getOrderClassify());
+    }
+
+    @Override
+    public List<DocumentByBomVo> getDocumentByBom(GetDocumentDto dto) {
+        return statementOfAccountService.getBomDocument(getIdList(dto), dto.getOrderClassify());
+    }
+
+    @Override
+    public List<DocumentByOrderVo> getDocumentByOrder(GetDocumentDto dto) {
+        return statementOfAccountService.getOrderDocument(getIdList(dto), dto.getOrderClassify());
+    }
+
+    @Override
+    public void export(ExportDocumentDto dto, int type) {
+
+        List<Long> idList = Arrays.stream(dto.getIdGroupConcat().split(","))
+                .map(Convert::toLong)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+
+        String departmentName = dto.getDepartmentName();
+        String beginDate = dto.getBeginDate();
+        String endDate = dto.getEndDate();
+        Integer orderClassify = dto.getOrderClassify();
+
+        switch (type) {
+            case 1:
+                statementOfAccountExportService.exportDocumentBySku(idList, departmentName, beginDate, endDate, orderClassify);
+                break;
+            case 2:
+                statementOfAccountExportService.exportDocumentByBom(idList, departmentName, beginDate, endDate, orderClassify);
+                break;
+            case 3:
+                excelGenerateLogService.generateExcel(ExcelTypeEnum.STATISTICS_DOCUMENT_BY_ORDER,
+                        new DocumentByOrderExcelExportStrategy(idList, departmentName, beginDate, endDate, orderClassify),
+                        DateUtil.formatDate(new Date()) + " " + OrderClassifyEnum.getEnum(orderClassify).getValue() + "-订单对账报表");
+                break;
+            default:
+                throw new ServiceException("未知对账单类型");
+        }
+    }
+
+    @Override
+    public Page<DocumentByOrderVo> salesOutWarehouseDetails(SalesOutWarehouseDetailsDto dto) {
+
+        // 对账单条件查询
+        List<StatementOfAccount> statementOfAccountList = null;
+        List<Long> statementOfAccountIdList = null;
+
+        if (!ObjectUtil.isAllEmpty(dto.getBeginTime(), dto.getEndTime())) {
+            statementOfAccountList = statementOfAccountService.list(q -> q
+                    .ge(ObjectUtil.isNotNull(dto.getBeginTime()), BasePo::getCreateTime, dto.getBeginTime())
+                    .le(ObjectUtil.isNotNull(dto.getEndTime()), BasePo::getCreateTime, dto.getEndTime()));
+
+            if (statementOfAccountList.isEmpty()) {
+                return new Page<>();
+            }
+            statementOfAccountIdList = statementOfAccountList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+        }
+
+        // sku条件查询
+        List<Long> orderIdList = null;
+        if (!StrUtil.isAllBlank(dto.getSkuSpecCode(), dto.getSkuSpecName())) {
+            List<SkuSpec> skuSpecList = skuSpecService.list(q -> q
+                    .like(StrUtil.isNotBlank(dto.getSkuSpecCode()), SkuSpec::getCode, dto.getSkuSpecCode())
+                    .like(StrUtil.isNotBlank(dto.getSkuSpecName()), SkuSpec::getName, dto.getSkuSpecName()));
+
+            if (skuSpecList.isEmpty()) {
+                return new Page<>();
+            }
+            List<Long> skuSpecIdList = skuSpecList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+
+            List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getSkuSpecId, skuSpecIdList));
+            if (orderSkuList.isEmpty()) {
+                return new Page<>();
+            }
+
+            orderIdList = orderSkuList.stream().map(OrderSku::getOrderId).collect(Collectors.toList());
+        }
+
+        Page<OrderInfo> page = dto.getPage();
+        page.setSearchCount(dto.getSearchCount());
+
+        // 查询订单分页
+        orderInfoService.page(page, Wrappers.lambdaQuery(OrderInfo.class)
+                .in(ObjectUtil.isNotEmpty(orderIdList), BaseIdPo::getId, orderIdList)
+                .in(ObjectUtil.isNotEmpty(statementOfAccountIdList), OrderInfo::getStatementOfAccountId, statementOfAccountIdList)
+                .isNotNull(ObjectUtil.isEmpty(statementOfAccountIdList), OrderInfo::getStatementOfAccountId)
+                .eq(ObjectUtil.isNotNull(dto.getDepartmentId()), OrderInfo::getDepartmentId, dto.getDepartmentId())
+                .and(StrUtil.isNotBlank(dto.getCode()), q -> q
+                        .like(OrderInfo::getCode, dto.getCode()).or().like(OrderInfo::getWlnCode, dto.getCode()))
+                .orderByDesc(OrderInfo::getStatementOfAccountId)
+        );
+
+        List<OrderInfo> records = page.getRecords();
+
+        if (records.isEmpty()) {
+            return new Page<>();
+        }
+
+        // 赋值订单sku,包材
+        List<DocumentByOrderVo> orderDocumentByOrderList = statementOfAccountService.getOrderDocumentByOrderList(records);
+
+        // 赋值事业部名称
+        departmentService.attributeAssign(orderDocumentByOrderList, DocumentByOrderVo::getDepartmentId, (item, department) -> {
+            item.setDepartmentName(department.getName());
+        });
+
+        // 赋值对账时间
+        if (statementOfAccountList == null) {
+            statementOfAccountList = statementOfAccountService.listByIds(
+                    records.stream().map(OrderInfo::getStatementOfAccountId).collect(Collectors.toList()));
+        }
+        Map<Long, StatementOfAccount> map = statementOfAccountList.stream().collect(Collectors.toMap(BaseIdPo::getId, Function.identity()));
+
+        for (DocumentByOrderVo documentByOrderVo : orderDocumentByOrderList) {
+            Long statementOfAccountId = documentByOrderVo.getStatementOfAccountId();
+            StatementOfAccount statementOfAccount = map.get(statementOfAccountId);
+            documentByOrderVo.setStatementOfAccountTime(statementOfAccount.getCreateTime());
+        }
+
+        Page<DocumentByOrderVo> result = new Page<>();
+        result.setTotal(page.getTotal());
+        result.setRecords(orderDocumentByOrderList);
+        result.setPages(page.getPages());
+        result.setSize(page.getSize());
+
+        return result;
+    }
+
+    @Override
+    public void exportSalesOutWarehouseDetails(SalesOutWarehouseDetailsDto dto) {
+
+        excelGenerateLogService.generateExcel(ExcelTypeEnum.SALES_OUT_WAREHOUSE_DETAILS,
+                new SalesOutWarehouseDetailsExportStrategy(this, dto),
+                DateUtil.formatDate(new Date()) + " 销售出货明细");
+    }
+
+    @Override
+    public Page<DocumentByRevenueCostVo> salesRevenueCostPage(SalesRevenueCostSelectDto dto) {
+        // 对账单条件查询
+        List<StatementOfAccount> statementOfAccountList = null;
+        List<Long> statementOfAccountIdList = null;
+
+        if (!ObjectUtil.isAllEmpty(dto.getBeginTime(), dto.getEndTime())) {
+            statementOfAccountList = statementOfAccountService.list(q -> q
+                    .ge(ObjectUtil.isNotNull(dto.getBeginTime()), BasePo::getCreateTime, dto.getBeginTime())
+                    .le(ObjectUtil.isNotNull(dto.getEndTime()), BasePo::getCreateTime, dto.getEndTime()));
+
+            if (statementOfAccountList.isEmpty()) {
+                return new Page<>();
+            }
+            statementOfAccountIdList = statementOfAccountList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+        }
+
+        // sku条件查询
+        List<Long> orderIdList = null;
+        if (!StrUtil.isAllBlank(dto.getSkuSpecCode(), dto.getSkuSpecName())) {
+            List<SkuSpec> skuSpecList = skuSpecService.list(q -> q
+                    .like(StrUtil.isNotBlank(dto.getSkuSpecCode()), SkuSpec::getCode, dto.getSkuSpecCode())
+                    .like(StrUtil.isNotBlank(dto.getSkuSpecName()), SkuSpec::getName, dto.getSkuSpecName()));
+
+            if (skuSpecList.isEmpty()) {
+                return new Page<>();
+            }
+            List<Long> skuSpecIdList = skuSpecList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+
+            List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getSkuSpecId, skuSpecIdList));
+            if (orderSkuList.isEmpty()) {
+                return new Page<>();
+            }
+
+            orderIdList = orderSkuList.stream().map(OrderSku::getOrderId).collect(Collectors.toList());
+        }
+
+        Page<OrderInfo> page = dto.getPage();
+
+        // 查询订单分页
+        orderInfoService.page(page, Wrappers.lambdaQuery(OrderInfo.class)
+                .eq(OrderInfo::getStatus, OrderStatusEnum.COMPLETION_PRODUCTION.getKey())
+                .in(ObjectUtil.isNotEmpty(orderIdList), BaseIdPo::getId, orderIdList)
+                .in(ObjectUtil.isNotEmpty(statementOfAccountIdList), OrderInfo::getStatementOfAccountId, statementOfAccountIdList)
+                .isNotNull(ObjectUtil.isEmpty(statementOfAccountIdList), OrderInfo::getStatementOfAccountId)
+                .eq(ObjectUtil.isNotNull(dto.getDepartmentId()), OrderInfo::getDepartmentId, dto.getDepartmentId())
+                .and(StrUtil.isNotBlank(dto.getCode()), q -> q
+                        .like(OrderInfo::getCode, dto.getCode()).or().like(OrderInfo::getWlnCode, dto.getCode()))
+                .orderByDesc(OrderInfo::getStatementOfAccountId)
+        );
+
+        List<OrderInfo> records = page.getRecords();
+
+        if (records.isEmpty()) {
+            return new Page<>();
+        }
+        Map<Long, OrderInfo> orderInfoMap = records.stream().collect(Collectors.toMap(BaseIdPo::getId, item -> item, (v1, v2) -> v2));
+        List<Long> orderIds = records.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+        List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIds));
+        // 获取sku详情数据
+        List<Long> skuSpecIds = orderSkuList.stream().map(OrderSku::getSkuSpecId).collect(Collectors.toList());
+        Map<Long, SkuSpecBo> skuSpecBoMap = skuSpecService.getSkuSpecBoByIdList(skuSpecIds);
+        // 获取订单成品出库数据
+        Map<Long, InventoryFinishedOrderDetail> inventoryMap = inventoryFinishedOrderDetailService.mapKEntity(
+                InventoryFinishedOrderDetail::getOrderSkuId,
+                q -> q.eq(InventoryFinishedOrderDetail::getOperationType, 2)
+                        .in(InventoryFinishedOrderDetail::getOrderInfoId, orderIds)
+                        .in(InventoryFinishedOrderDetail::getOrderSkuId, skuSpecIds));
+        // 获取订单sku生产成本数据
+        Map<Long, OrderSkuProductionCost> productionCostMap = orderSkuProductionCostService.mapKEntity(OrderSkuProductionCost::getOrderSkuId,
+                q -> q.in(OrderSkuProductionCost::getOrderId, orderIds));
+        Integer[] serialNumber = {1};
+        List<DocumentByRevenueCostVo> documentByRevenueCostVos = orderSkuList.stream()
+                .map(item -> {
+                    OrderInfo orderInfo = orderInfoMap.get(item.getOrderId());
+                    SkuSpecBo skuSpecBo = skuSpecBoMap.get(item.getSkuSpecId());
+                    InventoryFinishedOrderDetail inventoryDetail = inventoryMap.get(item.getSkuSpecId());
+                    // 规格
+                    String length = skuSpecBo.getLength() == null ? "0" : skuSpecBo.getLength().stripTrailingZeros().toPlainString();
+                    String width = skuSpecBo.getWidth() == null ? "0" : skuSpecBo.getWidth().stripTrailingZeros().toPlainString();
+                    String height = skuSpecBo.getHeight() == null ? "0" : skuSpecBo.getHeight().stripTrailingZeros().toPlainString();
+
+                    OrderSkuProductionCost productionCost = productionCostMap.get(item.getId());
+                    if (productionCost == null) {
+                        productionCost = new OrderSkuProductionCost();
+                        productionCost.setMaterialCost(BigDecimal.ZERO);
+                        productionCost.setAuxiliaryMaterialCost(BigDecimal.ZERO);
+                        productionCost.setProductPackagingMaterialCost(BigDecimal.ZERO);
+                        productionCost.setLogisticsPackagingMaterialCost(BigDecimal.ZERO);
+                        productionCost.setTotalAmount(BigDecimal.ZERO);
+                    }
+
+                    return DocumentByRevenueCostVo.builder()
+                            .orderId(item.getOrderId())
+                            .departmentId(orderInfo.getDepartmentId())
+                            .statementOfAccountId(orderInfo.getStatementOfAccountId())
+                            .salesDate(orderInfo.getShippingTime())
+                            .serialNumber(serialNumber[0]++)
+                            .code(orderInfo.getCode())
+                            .wlnCode(orderInfo.getWlnCode())
+                            .outStorageCode(inventoryDetail == null ? "" : inventoryDetail.getCode())
+                            .skuSpecCode(skuSpecBo.getSkuSpecCode())
+                            .skuSpecName(skuSpecBo.getSkuSpecName())
+                            .classifyName(skuSpecBo.getSkuClassifyName())
+                            .spec(length + " * " + width + " * " + height)
+                            .measuringUnit("PCS")
+                            .quantity(item.getQuantity())
+                            .salesUnitPrice(item.getUnitPrice()
+                                    .add(item.getCustomProcessingFee())
+                                    .add(item.getLssueFee())
+                                    .add(item.getDeliveryMaterialsFee())
+                                    .add(item.getPackingLabor())
+                                    .add(item.getPackagingMaterialCost())
+                                    .add(item.getManagementFee()))
+                            .issuingAmount(item.getLssueFee().multiply(item.getQuantity()))
+                            .otherAmount(item.getDeliveryMaterialsFee().multiply(item.getQuantity()))
+                            .materialCost(productionCost.getMaterialCost())
+                            .auxiliaryMaterialCost(productionCost.getAuxiliaryMaterialCost())
+                            .productPackagingMaterialCost(productionCost.getProductPackagingMaterialCost())
+                            .logisticsPackagingMaterialCost(productionCost.getLogisticsPackagingMaterialCost())
+                            .costSubtotal(productionCost.getTotalAmount())
+                            .build();
+                })
+                .peek(item -> item.setSalesAmount(item.getQuantity().multiply(item.getSalesUnitPrice())))
+                .peek(item -> {
+                    // 产品金额
+                    item.setProductAmount(item.getSalesAmount()
+                            .subtract(item.getIssuingAmount()).subtract(item.getOtherAmount()));
+                    // 毛利
+                    BigDecimal grossProfit = item.getSalesAmount().subtract(item.getCostSubtotal());
+                    // 毛利率
+                    String grossProfitRate;
+                    if (ObjectUtil.equals(item.getSalesAmount(), BigDecimal.ZERO)) {
+                        grossProfitRate = "0%";
+                    } else {
+                        grossProfitRate = grossProfit
+                                .divide(item.getSalesAmount(), 4, RoundingMode.HALF_UP)
+                                .multiply(new BigDecimal(100))
+                                .stripTrailingZeros().toPlainString() + "%";
+                    }
+                    item.setGrossProfit(grossProfit);
+                    item.setGrossProfitRate(grossProfitRate);
+                })
+                .collect(Collectors.toList());
+
+        // 赋值事业部名称
+        departmentService.attributeAssign(documentByRevenueCostVos, DocumentByRevenueCostVo::getDepartmentId, (item, department) -> {
+            item.setCustomerName(department.getName().startsWith("胜德实业") ? "胜德实业" : department.getName());
+            item.setDepartmentName(department.getName());
+        });
+
+        // 赋值对账时间
+        if (statementOfAccountList == null) {
+            statementOfAccountList = statementOfAccountService.listByIds(
+                    records.stream().map(OrderInfo::getStatementOfAccountId).collect(Collectors.toList()));
+        }
+        Map<Long, StatementOfAccount> map = statementOfAccountList.stream().collect(Collectors.toMap(BaseIdPo::getId, Function.identity()));
+
+        documentByRevenueCostVos.forEach(item -> {
+            Long statementOfAccountId = item.getStatementOfAccountId();
+            StatementOfAccount statementOfAccount = map.get(statementOfAccountId);
+            item.setSalesDate(statementOfAccount.getCreateTime());
+        });
+
+        Page<DocumentByRevenueCostVo> result = new Page<>();
+        result.setTotal(page.getTotal());
+        result.setRecords(documentByRevenueCostVos);
+        result.setPages(page.getPages());
+        result.setSize(page.getSize());
+        return result;
+    }
+
+    @Override
+    public void exportSalesRevenueCostData(SalesRevenueCostSelectDto dto) {
+        dto.setPageNum(1);
+        dto.setPageSize(999999999);
+        Page<DocumentByRevenueCostVo> page = this.salesRevenueCostPage(dto);
+        List<DocumentByRevenueCostVo> list = page.getRecords();
+        DefaultExportStrategy<DocumentByRevenueCostVo> defaultExportStrategy = new DefaultExportStrategy<>(
+                () -> list, DocumentByRevenueCostVo.class, "销售收入成本数据");
+
+        excelGenerateLogService.generateExcel(ExcelTypeEnum.DOCUMENT_BY_SALES_REVENUE_COST, defaultExportStrategy,
+                DateUtil.formatDate(new Date()) + " 销售收入成本表");
+    }
+
+    @Override
+    public void exportDeliveryOfGoodsExcel(List<Long> idList) {
+        List<String> orderWlnCodeList = getOrderWlnCodeList(idList);
+        List<OutboundOrder> outboundOrderList = getOutboundOrderList(orderWlnCodeList);
+        List<DeliveryOfGoodsVO> deliveryOfGoodsVOList = getDeliveryOfGoodsVOList(outboundOrderList);
+        ExcelUtil.export(response, "货物交接单", "货物交接单明细", deliveryOfGoodsVOList, DeliveryOfGoodsVO.class);
+    }
+
+    @Override
+    public List<Long> getNotSalesOutOfWarehouseOrder(GetDocumentDto dto) {
+        List<OrderInfo> orderList = orderInfoService.list(q -> q.in(OrderInfo::getStatementOfAccountId, getIdList(dto))
+                .eq(OrderInfo::getClassify, OrderClassifyEnum.NO_REASON_ORDER.getKey()));
+        if (orderList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<Long> orderIds = orderList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+        return inventoryFinishedOrderService.getNotSalesOutOfWarehouseOrderByIds(orderIds);
+    }
+
+    @Override
+    public void salesOutOfWarehouseByOrderIds(List<Long> idList) {
+        Assert.notEmpty(idList, "订单id不能为空");
+        // 查询在成品库的订单
+        List<InventoryFinishedOrder> list = inventoryFinishedOrderService.list(q -> q
+                .in(InventoryFinishedOrder::getOrderInfoId, idList)
+                .eq(InventoryFinishedOrder::getStatus, StatusConstant.YES));
+        List<Long> orderIds = list.stream().map(InventoryFinishedOrder::getOrderInfoId).collect(Collectors.toList());
+        // 筛选出不在库订单
+        idList.removeAll(orderIds);
+        if (!idList.isEmpty()) {
+            List<OrderInfo> orderInfoList = orderInfoService.listByIds(idList);
+            String orderCodes = orderInfoList.stream().map(OrderInfo::getWlnCode).collect(Collectors.joining(","));
+            throw new ServiceException("订单:" + orderCodes + "未在成品库中");
+        }
+        inventoryFinishedService.saleOutOfWarehouse(orderIds);
+    }
+
+    private List<Long> getIdList(GetDocumentDto dto) {
+
+        String idGroupConcat = dto.getIdGroupConcat();
+
+        List<Long> idList = Arrays.stream(idGroupConcat.split(","))
+                .map(Convert::toLong)
+                .distinct()
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        Assert.notEmpty(idList, "对账单id集合不能为空");
+
+        return idList;
+    }
+
+    /**
+     * 获取万里牛订单编号列表
+     *
+     * @param idList 对账单id列表
+     * @return 万里牛订单编号列表
+     */
+    private List<String> getOrderWlnCodeList(List<Long> idList) {
+        if (idList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<OrderInfo> list = orderInfoService.list(q -> q.in(OrderInfo::getStatementOfAccountId, idList));
+        return list.stream().map(OrderInfo::getWlnCode).collect(Collectors.toList());
+    }
+
+    /**
+     * 获取出库单列表
+     *
+     * @param orderWlnCodeList 万里牛订单编号列表
+     * @return 出库单列表
+     */
+    private List<OutboundOrder> getOutboundOrderList(List<String> orderWlnCodeList) {
+        if (orderWlnCodeList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        return outboundOrderService.list(q -> q.in(OutboundOrder::getOrderWlnCode, orderWlnCodeList));
+    }
+
+    /**
+     * 获取货物交接单数据列表
+     *
+     * @param outboundOrderList 出库单列表
+     * @return 货物交接单数据列表
+     */
+    private List<DeliveryOfGoodsVO> getDeliveryOfGoodsVOList(List<OutboundOrder> outboundOrderList) {
+        if (outboundOrderList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<String> skuSpecCodeList = outboundOrderList.stream().map(OutboundOrder::getSkuSpecCode).distinct().collect(Collectors.toList());
+        Map<String, String> map = skuSpecService.mapKV(SkuSpec::getCode, SkuSpec::getName, q -> q.in(SkuSpec::getCode, skuSpecCodeList));
+
+        return outboundOrderList.stream()
+                .map(item -> {
+                    DeliveryOfGoodsVO deliveryOfGoodsVO = new DeliveryOfGoodsVO();
+                    deliveryOfGoodsVO.setReceiptNumber(item.getCode());
+                    deliveryOfGoodsVO.setBusinessDate(item.getOutboundTime());
+                    deliveryOfGoodsVO.setWarehouse(getWarehouseName(item.getStorageCode()));
+                    deliveryOfGoodsVO.setSpec(map.get(item.getSkuSpecCode()));
+                    deliveryOfGoodsVO.setOutboundQuantity(item.getQuantity());
+                    deliveryOfGoodsVO.setOrderCode(item.getOrderCode());
+                    deliveryOfGoodsVO.setOrderWlnCode(item.getOrderWlnCode());
+                    deliveryOfGoodsVO.setExpress(item.getExpress());
+                    return deliveryOfGoodsVO;
+                })
+                .sorted(Comparator.comparing(DeliveryOfGoodsVO::getBusinessDate))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 通过仓库编码获取仓库名称
+     *
+     * @param code 仓库编码
+     * @return 仓库名称
+     */
+    private String getWarehouseName(String code) {
+        if (Objects.equals(code, "T007")) {
+            return "胜德体育仓-佰卓";
+        }
+        if (Objects.equals(code, "B012")) {
+            return "胜德体育仓-A9";
+        }
+        if (Objects.equals(code, "B013")) {
+            return "胜德体育仓-A1";
+        }
+        if (Objects.equals(code, "B014")) {
+            return "胜德体育仓-A8";
+        }
+
+        return code;
+    }
+
+}

+ 471 - 0
sd-business/src/main/java/com/sd/business/service/statement/impl/StatementOfAccountServiceImpl.java

@@ -2,27 +2,68 @@ package com.sd.business.service.statement.impl;
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fjhx.file.utils.ObsFileUtil;
+import com.ruoyi.common.constant.StatusConstant;
 import com.ruoyi.common.core.domain.BaseIdPo;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.framework.config.ThreadPoolConfig;
+import com.sd.business.entity.bom.bo.BomSpecBo;
+import com.sd.business.entity.department.po.Department;
+import com.sd.business.entity.excel.enums.ExcelTypeEnum;
+import com.sd.business.entity.order.enums.OrderClassifyEnum;
 import com.sd.business.entity.order.po.OrderInfo;
+import com.sd.business.entity.order.po.OrderSku;
+import com.sd.business.entity.order.po.OrderSkuBom;
+import com.sd.business.entity.sku.po.SkuSpec;
+import com.sd.business.entity.statement.dto.FileUploadDto;
 import com.sd.business.entity.statement.dto.StatementOfAccountDto;
 import com.sd.business.entity.statement.dto.StatementOfAccountSelectDto;
 import com.sd.business.entity.statement.po.StatementOfAccount;
+import com.sd.business.entity.statement.vo.DocumentByBomVo;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.entity.statement.vo.DocumentBySkuVo;
 import com.sd.business.entity.statement.vo.StatementOfAccountVo;
+import com.sd.business.entity.statement.vo.StatementOrderClassifyTotalCountVo;
 import com.sd.business.mapper.statement.StatementOfAccountMapper;
+import com.sd.business.service.bom.BomSpecService;
+import com.sd.business.service.department.DepartmentService;
+import com.sd.business.service.excel.ExcelGenerateLogService;
 import com.sd.business.service.order.OrderInfoService;
+import com.sd.business.service.order.OrderSkuBomService;
+import com.sd.business.service.order.OrderSkuService;
+import com.sd.business.service.sku.SkuSpecService;
+import com.sd.business.service.statement.StatementOfAccountExportService;
 import com.sd.business.service.statement.StatementOfAccountService;
+import com.sd.business.strategy.impl.DocumentByOrderExcelExportStrategy;
 import com.sd.business.util.code.CodeEnum;
 import com.sd.framework.util.Assert;
 import com.sd.framework.util.sql.Sql;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.comparing;
 
 
 /**
@@ -39,6 +80,32 @@ public class StatementOfAccountServiceImpl extends ServiceImpl<StatementOfAccoun
     @Autowired
     private OrderInfoService orderInfoService;
 
+
+    @Autowired
+    private OrderSkuService orderSkuService;
+
+    @Autowired
+    private OrderSkuBomService orderSkuBomService;
+
+    @Autowired
+    private DepartmentService departmentService;
+
+    @Autowired
+    private SkuSpecService skuSpecService;
+
+    @Autowired
+    private BomSpecService bomSpecService;
+
+    @Autowired
+    private StatementOfAccountExportService statementOfAccountExportService;
+
+    @Qualifier(ThreadPoolConfig.threadPoolTaskExecutor)
+    @Autowired
+    private ThreadPoolExecutor threadPoolExecutor;
+
+    @Autowired
+    private ExcelGenerateLogService excelGenerateLogService;
+
     @Override
     public Page<StatementOfAccountVo> getPage(StatementOfAccountSelectDto dto) {
 
@@ -131,4 +198,408 @@ public class StatementOfAccountServiceImpl extends ServiceImpl<StatementOfAccoun
         ObsFileUtil.removeFile(id);
     }
 
+
+    @Override
+    public void editFile(FileUploadDto dto, int type) {
+        ObsFileUtil.editFile(dto.getFileList(), dto.getId(), type);
+    }
+
+    @Override
+    public List<DocumentBySkuVo> getSkuDocument(List<Long> statementOfAccountIdList, Integer orderClassify) {
+
+        // 获取订单id列表
+        List<Long> orderIdList = getOrderIdList(statementOfAccountIdList, orderClassify);
+
+        if (orderIdList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        // 获取订单sku
+        List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIdList));
+
+        // 生成结果集
+        List<DocumentBySkuVo> documentBySkuVoList = orderSkuList.stream()
+                .map(item -> DocumentBySkuVo.builder()
+                        .skuSpecId(item.getSkuSpecId())
+                        .orderId(item.getOrderId())
+                        .quantity(item.getQuantity())
+                        .unitPrice(item.getUnitPrice()
+                                .add(item.getCustomProcessingFee())
+                                .add(item.getLssueFee())
+                                .add(item.getDeliveryMaterialsFee())
+                                .add(item.getPackingLabor())
+                                .add(item.getPackagingMaterialCost())
+                                .add(item.getManagementFee())
+                        )
+                        .build())
+                .peek(item -> item.setSubtotal(item.getQuantity().multiply(item.getUnitPrice()).setScale(2, RoundingMode.HALF_UP)))
+                .peek(item -> item.setTotal(item.getSubtotal()))
+                .peek(item -> item.setUnitPrice(item.getUnitPrice().setScale(2, RoundingMode.HALF_UP)))
+                .collect(Collectors.toList());
+
+        // 查询赠品sku
+        List<Long> skuSpecIds = documentBySkuVoList.stream().map(DocumentBySkuVo::getSkuSpecId).collect(Collectors.toList());
+        Map<Long, SkuSpec> skuSpecMap = skuSpecService.byIdsToMap(skuSpecIds);
+        Set<Long> giftSkuSpecIds = skuSpecMap.values().stream()
+                .map(BaseIdPo::getId)
+                .collect(Collectors.toSet());
+
+        // 赋值sku规格品名和品号
+        for (DocumentBySkuVo documentBySkuVo : documentBySkuVoList) {
+            SkuSpec skuSpec = skuSpecMap.get(documentBySkuVo.getSkuSpecId());
+            if (skuSpec == null) {
+                continue;
+            }
+            documentBySkuVo.setSkuSpecCode(skuSpec.getCode());
+            documentBySkuVo.setSkuSpecName(skuSpec.getName());
+        }
+
+        // 合并单价、小计、sku规格id系统的对账数据
+        Collection<DocumentBySkuVo> documentBySkuVoCollection = documentBySkuVoList.stream()
+                .filter(item -> giftSkuSpecIds.isEmpty() || !giftSkuSpecIds.contains(item.getSkuSpecId()))
+                .sorted(comparing(DocumentBySkuVo::getSkuSpecCode))
+                .collect(Collectors.toMap(
+                        item -> item.getUnitPrice() + ":" + item.getSkuSpecId(),
+                        Function.identity(),
+                        (v1, v2) -> {
+                            v1.setQuantity(v1.getQuantity().add(v2.getQuantity()));
+                            v1.setSubtotal(v1.getSubtotal().add(v2.getSubtotal()));
+                            v1.setTotal(v1.getTotal().add(v2.getTotal()));
+                            return v1;
+                        }
+                )).values();
+
+        return new ArrayList<>(documentBySkuVoCollection);
+    }
+
+    @Override
+    public List<DocumentByBomVo> getBomDocument(List<Long> statementOfAccountIdList, Integer orderClassify) {
+
+        // 获取订单id列表
+        List<Long> orderIdList = getOrderIdList(statementOfAccountIdList, orderClassify);
+        if (orderIdList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        // 获取订单sku
+        List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIdList));
+
+        // 主材bom
+        List<DocumentByBomVo> result = orderSkuList.stream()
+                .map(item -> DocumentByBomVo.builder()
+                        .bomSpecId(item.getBomSpecId())
+                        .orderId(item.getOrderId())
+                        .quantity(item.getQuantity())
+                        .unitPrice(item.getUnitPrice())
+                        .lssueFeeSummary(item.getLssueFee().multiply(item.getQuantity()))
+                        .deliveryMaterialsFeeSummary(item.getDeliveryMaterialsFee().multiply(item.getQuantity()))
+                        .packingLaborSummary(item.getPackingLabor().multiply(item.getQuantity()))
+                        .managementFeeSummary(item.getManagementFee().multiply(item.getQuantity()))
+                        .build())
+                .peek(item -> item.setSubtotal(
+                        item.getUnitPrice()
+                                .multiply(item.getQuantity())
+                                .add(item.getLssueFeeSummary())
+                                .add(item.getDeliveryMaterialsFeeSummary())
+                                .add(item.getPackingLaborSummary())
+                                .add(item.getManagementFeeSummary())
+                                .setScale(2, RoundingMode.HALF_UP)
+                ))
+                .peek(item -> item.setTotal(item.getSubtotal()))
+                .collect(Collectors.toList());
+
+        // 赋值主材bom品名品号
+        bomSpecService.attributeAssign(result, DocumentByBomVo::getBomSpecId, (item, bomSpec) -> {
+            item.setBomSpecCode(bomSpec.getCode());
+            item.setBomSpecName(bomSpec.getName());
+        });
+
+        // 合并同加个同规格主材bom,数量相加
+        Collection<DocumentByBomVo> documentByBomVoCollection = result.stream()
+                .sorted(comparing(DocumentByBomVo::getBomSpecCode))
+                .collect(Collectors.toMap(
+                        item -> item.getUnitPrice() + ":" + item.getBomSpecId(),
+                        Function.identity(),
+                        (v1, v2) -> {
+                            v1.setQuantity(v1.getQuantity().add(v2.getQuantity()));
+                            v1.setLssueFeeSummary(v1.getLssueFeeSummary().add(v2.getLssueFeeSummary()));
+                            v1.setDeliveryMaterialsFeeSummary(v1.getDeliveryMaterialsFeeSummary().add(v2.getDeliveryMaterialsFeeSummary()));
+                            v1.setPackingLaborSummary(v1.getPackingLaborSummary().add(v2.getPackingLaborSummary()));
+                            v1.setManagementFeeSummary(v1.getManagementFeeSummary().add(v2.getManagementFeeSummary()));
+                            v1.setSubtotal(v1.getSubtotal().add(v2.getSubtotal()));
+                            v1.setTotal(v1.getSubtotal());
+                            return v1;
+                        }
+                )).values();
+
+        // 赋值合并后结果
+        result = new ArrayList<>(documentByBomVoCollection);
+        // 按品名升序排序
+        result.sort(comparing(DocumentByBomVo::getBomSpecName));
+
+        Map<Long, BigDecimal> orderSkuMap = orderSkuList.stream().collect(Collectors.toMap(BaseIdPo::getId, OrderSku::getQuantity));
+
+        // 包材bom
+        List<OrderSkuBom> orderSkuBomList = orderSkuBomService.list(q -> q.in(OrderSkuBom::getOrderId, orderIdList));
+        List<DocumentByBomVo> bomVoList = orderSkuBomList.stream().map(item ->
+                DocumentByBomVo.builder()
+                        .bomSpecId(item.getBomSpecId())
+                        .quantity(item.getQuantity().multiply(orderSkuMap.get(item.getOrderSkuId())))
+                        .unitPrice(item.getUnitPrice())
+                        .subtotal(item.getUnitPrice().multiply(item.getQuantity().multiply(orderSkuMap.get(item.getOrderSkuId()))))
+                        .total(item.getUnitPrice().multiply(item.getQuantity().multiply(orderSkuMap.get(item.getOrderSkuId()))))
+                        .build()
+        ).collect(Collectors.toList());
+
+        // 赋值包材bom品名品号
+        bomSpecService.attributeAssign(bomVoList, DocumentByBomVo::getBomSpecId, (item, bomSpec) -> {
+            item.setBomSpecCode(bomSpec.getCode());
+            item.setBomSpecName(bomSpec.getName());
+        });
+
+        // 合并同加个同规格包材bom,数量相加
+        Collection<DocumentByBomVo> bomValues = bomVoList.stream()
+                .sorted(comparing(DocumentByBomVo::getBomSpecCode))
+                .collect(Collectors.toMap(
+                        item -> item.getUnitPrice() + ":" + item.getBomSpecId(),
+                        Function.identity(),
+                        (v1, v2) -> {
+                            v1.setQuantity(v1.getQuantity().add(v2.getQuantity()));
+                            v1.setSubtotal(v1.getSubtotal().add(v2.getSubtotal()));
+                            v1.setTotal(v1.getSubtotal());
+                            return v1;
+                        }
+                )).values();
+
+        // 合并主材包材
+        result.addAll(bomValues);
+
+        return result;
+    }
+
+    @Override
+    public List<DocumentByOrderVo> getOrderDocument(List<Long> statementOfAccountId, Integer orderClassify) {
+
+        Assert.notEmpty(statementOfAccountId, "对账单id不能为空");
+        List<OrderInfo> orderList = orderInfoService.list(q -> q
+                .in(OrderInfo::getStatementOfAccountId, statementOfAccountId)
+                .eq(OrderInfo::getClassify, orderClassify));
+
+        return getOrderDocumentByOrderList(orderList);
+    }
+
+    @Override
+    public List<DocumentByOrderVo> getOrderDocumentByOrderList(List<OrderInfo> orderList) {
+        if (orderList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<DocumentByOrderVo> result = orderList.stream().map(item -> {
+            DocumentByOrderVo documentByOrderVo = new DocumentByOrderVo();
+            documentByOrderVo.setOrderId(item.getId());
+            documentByOrderVo.setWlnCreateTime(ObjectUtil.defaultIfNull(item.getWlnCreateTime(), item.getCreateTime()));
+            documentByOrderVo.setCode(item.getCode());
+            documentByOrderVo.setWlnCode(item.getWlnCode());
+            documentByOrderVo.setTotal(item.getTotalAmount());
+
+            documentByOrderVo.setSourcePlatform(item.getSourcePlatform());
+            documentByOrderVo.setShopName(item.getShopName());
+            documentByOrderVo.setDepartmentId(item.getDepartmentId());
+            documentByOrderVo.setStatementOfAccountId(item.getStatementOfAccountId());
+
+            return documentByOrderVo;
+        }).collect(Collectors.toList());
+
+        List<Long> orderIdList = orderList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+        List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIdList));
+
+        SecurityContext context = SecurityContextHolder.getContext();
+
+        CompletableFuture<List<DocumentByOrderVo.SkuSpec>> skuSpecListCompletableFuture = CompletableFuture.supplyAsync(
+                () -> {
+                    SecurityContextHolder.setContext(context);
+                    return getSkuSpecList(orderSkuList);
+                }, threadPoolExecutor);
+
+        CompletableFuture<List<DocumentByOrderVo.BomSpec>> bomSpecListCompletableFuture = CompletableFuture.supplyAsync(
+                () -> {
+                    SecurityContextHolder.setContext(context);
+                    return getBomSpecList(orderIdList, orderSkuList);
+                }, threadPoolExecutor);
+
+        // 获取订单bom
+        List<DocumentByOrderVo.BomSpec> bomSpecList = bomSpecListCompletableFuture.join();
+
+        // sku赋值bom
+        Map<Long, List<DocumentByOrderVo.BomSpec>> bomSpecMap = bomSpecList.stream()
+                .collect(Collectors.groupingBy(DocumentByOrderVo.BomSpec::getOrderSkuId));
+
+        // 获取订单sku
+        List<DocumentByOrderVo.SkuSpec> skuSpecList = skuSpecListCompletableFuture.join();
+
+        for (DocumentByOrderVo.SkuSpec skuSpec : skuSpecList) {
+            skuSpec.setBomSpecList(bomSpecMap.getOrDefault(skuSpec.getOrderSkuId(), Collections.emptyList()));
+        }
+
+        // 订单赋值sku
+        Map<Long, List<DocumentByOrderVo.SkuSpec>> skuSpecMap = skuSpecList.stream()
+                .collect(Collectors.groupingBy(DocumentByOrderVo.SkuSpec::getOrderId));
+        result.forEach(item -> item.setSkuSpecList(skuSpecMap.getOrDefault(item.getOrderId(), Collections.emptyList())));
+
+        return result;
+    }
+
+    @Override
+    public void export(Long id, Integer orderClassify, int type) {
+
+        StatementOfAccount statementOfAccount = getById(id);
+        Assert.notNull(statementOfAccount, "没有找到对账单");
+
+        Department department = departmentService.getById(statementOfAccount.getDepartmentId());
+        Assert.notNull(department, "没有找到事业部");
+
+        Date timePeriod = statementOfAccount.getTimePeriod();
+        String date = timePeriod != null ? DateUtil.formatDate(timePeriod) : StringPool.EMPTY;
+        String departmentName = department.getName();
+
+        List<Long> idList = Collections.singletonList(id);
+
+        switch (type) {
+            case 1:
+                statementOfAccountExportService.exportDocumentBySku(idList, departmentName, date, date, orderClassify);
+                break;
+            case 2:
+                statementOfAccountExportService.exportDocumentByBom(idList, departmentName, date, date, orderClassify);
+                break;
+            case 3:
+                excelGenerateLogService.generateExcel(ExcelTypeEnum.STATISTICS_DOCUMENT_BY_ORDER,
+                        new DocumentByOrderExcelExportStrategy(idList, departmentName, date, date, orderClassify),
+                        DateUtil.formatDate(new Date()) + " " + OrderClassifyEnum.getEnum(orderClassify).getValue() + "-订单对账单");
+                break;
+            default:
+                throw new ServiceException("未知对账单类型");
+        }
+
+    }
+
+    @Override
+    public String getOrderWlnCodeStr(List<Long> idList) {
+        List<OrderInfo> list = orderInfoService.list(q -> q.in(OrderInfo::getStatementOfAccountId, idList));
+        List<String> wlnCodeList = list.stream().map(OrderInfo::getWlnCode).filter(ObjectUtil::isNotNull).collect(Collectors.toList());
+        return JSON.toJSONString(wlnCodeList);
+    }
+
+    @Override
+    public StatementOrderClassifyTotalCountVo getOrderClassifyTotalCount(List<Long> idList) {
+        Assert.notEmpty(idList, "对账单id不能为空");
+        return orderInfoService.getOrderClassifyTotalCount(idList);
+    }
+
+    @Override
+    public Long getNotCheckCount() {
+        // 查询佰卓和实业的事业部id
+        List<Department> departmentList = departmentService.list(q -> q.like(Department::getName, "实业").or().eq(Department::getName, "佰卓").select(BaseIdPo::getId));
+        List<Long> departmentIds = departmentList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+        return this.count(q -> q.in(StatementOfAccount::getDepartmentId, departmentIds)
+                .eq(StatementOfAccount::getCheckStatus, StatusConstant.NO));
+    }
+
+    /**
+     * 根据对账单id获取对账订单id列表
+     */
+    private List<Long> getOrderIdList(List<Long> statementOfAccountIdList, Integer orderClassify) {
+        Assert.notEmpty(statementOfAccountIdList, "对账单id不能为空");
+        List<OrderInfo> orderList = orderInfoService.list(q -> q.in(OrderInfo::getStatementOfAccountId, statementOfAccountIdList)
+                .eq(OrderInfo::getClassify, orderClassify));
+        return orderList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+    }
+
+    /**
+     * 获取订单sku
+     */
+    private List<DocumentByOrderVo.SkuSpec> getSkuSpecList(List<OrderSku> orderSkuList) {
+
+        List<DocumentByOrderVo.SkuSpec> skuSpecList = orderSkuList.stream()
+                .map(item -> {
+                    DocumentByOrderVo.SkuSpec skuSpec = new DocumentByOrderVo.SkuSpec();
+                    skuSpec.setOrderId(item.getOrderId());
+                    skuSpec.setOrderSkuId(item.getId());
+                    skuSpec.setSkuSpecId(item.getSkuSpecId());
+                    skuSpec.setQuantity(item.getQuantity());
+                    skuSpec.setUnitPrice(item.getUnitPrice()
+                            .add(item.getCustomProcessingFee())
+                            .add(item.getLssueFee())
+                            .add(item.getDeliveryMaterialsFee())
+                            .add(item.getPackingLabor())
+                            .add(item.getPackagingMaterialCost())
+                            .add(item.getManagementFee()));
+                    return skuSpec;
+                })
+                .peek(item -> item.setSubtotal(item.getQuantity().multiply(item.getUnitPrice()).setScale(2, RoundingMode.HALF_UP)))
+                .peek(item -> item.setUnitPrice(item.getUnitPrice().setScale(2, RoundingMode.HALF_UP)))
+                .collect(Collectors.toList());
+
+        skuSpecService.attributeAssign(skuSpecList, DocumentByOrderVo.SkuSpec::getSkuSpecId, (item, skuSpec) -> {
+            item.setSkuSpecCode(skuSpec.getCode());
+            item.setSkuSpecName(skuSpec.getName());
+        });
+
+        return skuSpecList;
+    }
+
+    /**
+     * 获取订单bom
+     */
+    private List<DocumentByOrderVo.BomSpec> getBomSpecList(List<Long> orderIdList, List<OrderSku> orderSkuList) {
+
+        // 主材
+        List<DocumentByOrderVo.BomSpec> bomSpecList = orderSkuList.stream()
+                .map(item -> {
+                    DocumentByOrderVo.BomSpec bomSpec = new DocumentByOrderVo.BomSpec();
+                    bomSpec.setOrderSkuId(item.getId());
+                    bomSpec.setBomSpecId(item.getBomSpecId());
+                    bomSpec.setQuantity(item.getQuantity());
+                    bomSpec.setUnitPrice(item.getUnitPrice());
+                    bomSpec.setLssueFeeSummary(item.getLssueFee());
+                    bomSpec.setDeliveryMaterialsFeeSummary(item.getDeliveryMaterialsFee());
+                    bomSpec.setPackingLaborSummary(item.getPackingLabor());
+                    bomSpec.setManagementFeeSummary(item.getManagementFee());
+                    return bomSpec;
+                })
+                .collect(Collectors.toList());
+
+        Map<Long, BigDecimal> map = bomSpecList.stream().collect(
+                Collectors.toMap(DocumentByOrderVo.BomSpec::getOrderSkuId, DocumentByOrderVo.BomSpec::getQuantity));
+
+        // 包材
+        List<OrderSkuBom> orderSkuBomList = orderSkuBomService.list(q -> q.in(OrderSkuBom::getOrderId, orderIdList));
+        List<DocumentByOrderVo.BomSpec> packBomSpecList = orderSkuBomList.stream()
+                .map(item -> {
+                    DocumentByOrderVo.BomSpec bomSpec = new DocumentByOrderVo.BomSpec();
+                    bomSpec.setOrderSkuId(item.getOrderSkuId());
+                    bomSpec.setBomSpecId(item.getBomSpecId());
+                    bomSpec.setQuantity(item.getQuantity());
+                    bomSpec.setUnitPrice(item.getUnitPrice());
+                    return bomSpec;
+                })
+                .peek(item -> item.setQuantity(ObjectUtil.equals(map.get(item.getOrderSkuId()), BigDecimal.ZERO) ? item.getQuantity() : map.get(item.getOrderSkuId()).multiply(item.getQuantity())))
+                .collect(Collectors.toList());
+
+        // 赋值
+        bomSpecList.addAll(packBomSpecList);
+
+        List<Long> bomSpecIdList = bomSpecList.stream().map(DocumentByOrderVo.BomSpec::getBomSpecId).collect(Collectors.toList());
+        Map<Long, BomSpecBo> bomSpecBoMap = bomSpecService.getBomSpecBo(bomSpecIdList);
+
+        for (DocumentByOrderVo.BomSpec bomSpec : bomSpecList) {
+            BomSpecBo bomSpecBo = bomSpecBoMap.get(bomSpec.getBomSpecId());
+
+            bomSpec.setBomSpecCode(bomSpecBo.getBomSpecCode());
+            bomSpec.setBomSpecName(bomSpecBo.getBomSpecName());
+            bomSpec.setClassifyName(bomSpecBo.getClassifyName());
+        }
+
+        return bomSpecList;
+    }
+
 }

+ 11 - 0
sd-business/src/main/java/com/sd/business/strategy/ExcelExportStrategy.java

@@ -0,0 +1,11 @@
+package com.sd.business.strategy;
+
+import java.io.InputStream;
+
+public interface ExcelExportStrategy<T> {
+
+    T getData();
+
+    InputStream getInputStream(T data);
+
+}

+ 46 - 0
sd-business/src/main/java/com/sd/business/strategy/impl/DefaultExportStrategy.java

@@ -0,0 +1,46 @@
+package com.sd.business.strategy.impl;
+
+import cn.hutool.core.io.IoUtil;
+import com.alibaba.excel.EasyExcel;
+import com.sd.business.strategy.ExcelExportStrategy;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.function.Supplier;
+
+public class DefaultExportStrategy<T> implements ExcelExportStrategy<List<T>> {
+
+    private final Class<T> aClass;
+
+    private final Supplier<List<T>> supplier;
+
+    private final String sheetName;
+
+    public DefaultExportStrategy(Supplier<List<T>> supplier, Class<T> aClass, String sheetName) {
+        this.supplier = supplier;
+        this.aClass = aClass;
+        this.sheetName = sheetName;
+    }
+
+    @Override
+    public List<T> getData() {
+        return supplier.get();
+    }
+
+    @Override
+    public InputStream getInputStream(List<T> data) {
+
+        ByteArrayOutputStream os = null;
+
+        try {
+            os = new ByteArrayOutputStream();
+            EasyExcel.write(os, aClass).sheet(sheetName).doWrite(data);
+            return new ByteArrayInputStream(os.toByteArray());
+        } finally {
+            IoUtil.close(os);
+        }
+
+    }
+}

+ 155 - 0
sd-business/src/main/java/com/sd/business/strategy/impl/DocumentByOrderExcelExportStrategy.java

@@ -0,0 +1,155 @@
+package com.sd.business.strategy.impl;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import com.alibaba.excel.write.metadata.fill.FillConfig;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.ruoyi.common.exception.ServiceException;
+import com.sd.business.entity.statement.bo.ExportDocumentByOrderBo;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.service.statement.StatementOfAccountService;
+import com.sd.business.service.statement.impl.DocumentByOrderExcelCellMergeStrategy;
+import com.sd.business.strategy.ExcelExportStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 订单对账单
+ */
+@Slf4j
+public class DocumentByOrderExcelExportStrategy implements ExcelExportStrategy<Map<String, Object>> {
+
+    private static final StatementOfAccountService statementOfAccountService = SpringUtil.getBean(StatementOfAccountService.class);
+
+    private final List<Long> idList;
+    private final String departmentName;
+    private final String beginDate;
+    private final String endDate;
+    private final Integer orderClassify;
+
+    private List<DocumentByOrderVo> list;
+
+    public DocumentByOrderExcelExportStrategy(List<Long> idList, String departmentName, String beginDate, String endDate, Integer orderClassify) {
+        this.idList = idList;
+        this.departmentName = departmentName;
+        this.beginDate = beginDate;
+        this.endDate = endDate;
+        this.orderClassify = orderClassify;
+    }
+
+    @Override
+    public Map<String, Object> getData() {
+        list = statementOfAccountService.getOrderDocument(idList, orderClassify);
+
+        BigDecimal all = BigDecimal.ZERO;
+
+        List<ExportDocumentByOrderBo> exportDocumentByOrderBos = new ArrayList<>();
+        for (DocumentByOrderVo documentByOrderVo : list) {
+            List<DocumentByOrderVo.SkuSpec> skuSpecList = documentByOrderVo.getSkuSpecList();
+            for (DocumentByOrderVo.SkuSpec skuSpec : skuSpecList) {
+                List<DocumentByOrderVo.BomSpec> bomSpecList = skuSpec.getBomSpecList();
+                for (DocumentByOrderVo.BomSpec bomSpec : bomSpecList) {
+                    ExportDocumentByOrderBo exportDocumentByOrderBo = ExportDocumentByOrderBo.builder()
+                            .skuSpecCode(skuSpec.getSkuSpecCode())
+                            .skuSpecName(skuSpec.getSkuSpecName())
+                            .quantity(skuSpec.getQuantity())
+                            .unitPrice(skuSpec.getUnitPrice())
+                            .subtotal(skuSpec.getSubtotal())
+                            .wlnCreateTime(documentByOrderVo.getWlnCreateTime())
+                            .code(documentByOrderVo.getCode())
+                            .wlnCode(documentByOrderVo.getWlnCode())
+                            .total(documentByOrderVo.getTotal())
+                            .bomSpecCode(bomSpec.getBomSpecCode())
+                            .bomSpecName(bomSpec.getBomSpecName())
+                            .bomQuantity(bomSpec.getQuantity())
+                            .bomUnitPrice(bomSpec.getUnitPrice())
+                            .lssueFeeSummary(bomSpec.getLssueFeeSummary())
+                            .deliveryMaterialsFeeSummary(bomSpec.getDeliveryMaterialsFeeSummary())
+                            .packingLaborSummary(bomSpec.getPackingLaborSummary())
+                            .managementFeeSummary(bomSpec.getManagementFeeSummary())
+                            .build();
+                    exportDocumentByOrderBos.add(exportDocumentByOrderBo);
+                }
+            }
+
+            all = all.add(documentByOrderVo.getTotal());
+        }
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("department", StrUtil.isBlank(departmentName) ? StringPool.EMPTY : departmentName + StringPool.DASH);
+        map.put("beginDate", beginDate);
+        map.put("endDate", endDate);
+        map.put("all", all);
+        map.put("exportDocumentByOrderBos", exportDocumentByOrderBos);
+        return map;
+    }
+
+    @Override
+    public InputStream getInputStream(Map<String, Object> data) {
+        List<ExportDocumentByOrderBo> exportDocumentByOrderBos = (List<ExportDocumentByOrderBo>) data.remove("exportDocumentByOrderBos");
+
+        try {
+            String filePath = "tempExcel" + File.separator + IdWorker.getId() + ".xlsx";
+            File tempExcel = new File("tempExcel");
+            if (!tempExcel.exists()) {
+                tempExcel.mkdir();
+            }
+
+            ClassPathResource classPathResource = new ClassPathResource("template" + File.separator + "orderDocument.xlsx");
+            InputStream is = null;
+            BufferedOutputStream os = null;
+            ExcelWriter excelWriter = null;
+            try {
+                is = classPathResource.getInputStream();
+                os = new BufferedOutputStream(Files.newOutputStream(Paths.get(filePath)));
+                excelWriter = EasyExcel.write(os).withTemplate(is).build();
+                DocumentByOrderExcelCellMergeStrategy strategy = new DocumentByOrderExcelCellMergeStrategy(list);
+                WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(strategy).build();
+                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
+
+                excelWriter.fill(data, fillConfig, writeSheet);
+                for (List<ExportDocumentByOrderBo> documentByOrderBos : ListUtil.partition(exportDocumentByOrderBos, 3000)) {
+                    excelWriter.fill(documentByOrderBos, fillConfig, writeSheet);
+                }
+
+            } finally {
+                if (excelWriter != null) {
+                    excelWriter.finish();
+                    excelWriter.close();
+                }
+                IoUtil.close(os);
+                IoUtil.close(is);
+            }
+
+            File file = new File(filePath);
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(FileUtil.readBytes(file));
+            file.delete();
+
+            return inputStream;
+        } catch (IOException e) {
+            log.error("excel导出失败", e);
+            throw new ServiceException("excel导出失败");
+        }
+    }
+
+}

+ 154 - 0
sd-business/src/main/java/com/sd/business/strategy/impl/SalesOutWarehouseDetailsExportStrategy.java

@@ -0,0 +1,154 @@
+package com.sd.business.strategy.impl;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import com.alibaba.excel.write.metadata.fill.FillConfig;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.exception.ServiceException;
+import com.sd.business.entity.statement.bo.ExportDocumentByOrderBo;
+import com.sd.business.entity.statement.dto.SalesOutWarehouseDetailsDto;
+import com.sd.business.entity.statement.vo.DocumentByOrderVo;
+import com.sd.business.service.statement.impl.SalesOutWarehouseDetailsExcelCellMergeStrategy;
+import com.sd.business.service.statement.impl.StatementOfAccountMergeServiceImpl;
+import com.sd.business.strategy.ExcelExportStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 订单对账单
+ */
+@Slf4j
+public class SalesOutWarehouseDetailsExportStrategy implements ExcelExportStrategy<Map<String, Object>> {
+
+    private final SalesOutWarehouseDetailsDto dto;
+    private final StatementOfAccountMergeServiceImpl service;
+
+    private List<DocumentByOrderVo> list;
+
+    public SalesOutWarehouseDetailsExportStrategy(StatementOfAccountMergeServiceImpl service, SalesOutWarehouseDetailsDto dto) {
+        this.service = service;
+        this.dto = dto;
+    }
+
+    @Override
+    public Map<String, Object> getData() {
+
+        dto.setPageNum(1);
+        dto.setPageSize(999999999);
+        dto.setSearchCount(false);
+        Page<DocumentByOrderVo> documentByOrderVoPage = service.salesOutWarehouseDetails(dto);
+        list = documentByOrderVoPage.getRecords();
+
+        BigDecimal all = BigDecimal.ZERO;
+
+        List<ExportDocumentByOrderBo> exportDocumentByOrderBos = new ArrayList<>();
+        for (DocumentByOrderVo documentByOrderVo : list) {
+            List<DocumentByOrderVo.SkuSpec> skuSpecList = documentByOrderVo.getSkuSpecList();
+            for (DocumentByOrderVo.SkuSpec skuSpec : skuSpecList) {
+                List<DocumentByOrderVo.BomSpec> bomSpecList = skuSpec.getBomSpecList();
+                for (DocumentByOrderVo.BomSpec bomSpec : bomSpecList) {
+                    ExportDocumentByOrderBo exportDocumentByOrderBo = ExportDocumentByOrderBo.builder()
+                            .skuSpecCode(skuSpec.getSkuSpecCode())
+                            .skuSpecName(skuSpec.getSkuSpecName())
+                            .quantity(skuSpec.getQuantity())
+                            .unitPrice(skuSpec.getUnitPrice())
+                            .subtotal(skuSpec.getSubtotal())
+                            .wlnCreateTime(documentByOrderVo.getWlnCreateTime())
+                            .wlnCode(documentByOrderVo.getWlnCode())
+                            .total(documentByOrderVo.getTotal())
+                            .bomSpecCode(bomSpec.getBomSpecCode())
+                            .bomSpecName(bomSpec.getBomSpecName())
+                            .bomQuantity(bomSpec.getQuantity())
+                            .bomUnitPrice(bomSpec.getUnitPrice())
+                            .lssueFeeSummary(bomSpec.getLssueFeeSummary())
+                            .deliveryMaterialsFeeSummary(bomSpec.getDeliveryMaterialsFeeSummary())
+                            .packingLaborSummary(bomSpec.getPackingLaborSummary())
+                            .managementFeeSummary(bomSpec.getManagementFeeSummary())
+
+                            .shopName(documentByOrderVo.getShopName())
+                            .departmentName(documentByOrderVo.getDepartmentName())
+                            .statementOfAccountTime(documentByOrderVo.getStatementOfAccountTime())
+                            .code(documentByOrderVo.getWlnCode() == null ? null : documentByOrderVo.getCode())
+                            .mesCode(documentByOrderVo.getWlnCode() == null ? documentByOrderVo.getCode() : null)
+                            .classifyName(bomSpec.getClassifyName())
+                            .build();
+                    exportDocumentByOrderBos.add(exportDocumentByOrderBo);
+                }
+            }
+
+            all = all.add(documentByOrderVo.getTotal());
+        }
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("all", all);
+        map.put("exportDocumentByOrderBos", exportDocumentByOrderBos);
+        return map;
+    }
+
+    @Override
+    public InputStream getInputStream(Map<String, Object> data) {
+        List<ExportDocumentByOrderBo> exportDocumentByOrderBos = (List<ExportDocumentByOrderBo>) data.remove("exportDocumentByOrderBos");
+
+        try {
+            String filePath = "tempExcel" + File.separator + IdWorker.getId() + ".xlsx";
+            File tempExcel = new File("tempExcel");
+            if (!tempExcel.exists()) {
+                tempExcel.mkdir();
+            }
+
+            ClassPathResource classPathResource = new ClassPathResource("template" + File.separator + "salesOutWarehouseDetails.xlsx");
+            InputStream is = null;
+            BufferedOutputStream os = null;
+            ExcelWriter excelWriter = null;
+            try {
+                is = classPathResource.getInputStream();
+                os = new BufferedOutputStream(Files.newOutputStream(Paths.get(filePath)));
+                excelWriter = EasyExcel.write(os).withTemplate(is).build();
+                SalesOutWarehouseDetailsExcelCellMergeStrategy strategy = new SalesOutWarehouseDetailsExcelCellMergeStrategy(list);
+                WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(strategy).build();
+                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
+
+                excelWriter.fill(data, fillConfig, writeSheet);
+                for (List<ExportDocumentByOrderBo> documentByOrderBos : ListUtil.partition(exportDocumentByOrderBos, 3000)) {
+                    excelWriter.fill(documentByOrderBos, fillConfig, writeSheet);
+                }
+
+            } finally {
+                if (excelWriter != null) {
+                    excelWriter.finish();
+                    excelWriter.close();
+                }
+                IoUtil.close(os);
+                IoUtil.close(is);
+            }
+
+            File file = new File(filePath);
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(FileUtil.readBytes(file));
+            file.delete();
+
+            return inputStream;
+        } catch (IOException e) {
+            log.error("excel导出失败", e);
+            throw new ServiceException("excel导出失败");
+        }
+    }
+
+}

+ 21 - 0
sd-business/src/main/java/com/sd/business/util/StreamUtil.java

@@ -0,0 +1,21 @@
+package com.sd.business.util;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+public class StreamUtil {
+
+    /**
+     * 数组某个字段值相加
+     *
+     * @param list   数组
+     * @param mapper 字段
+     * @return 相加结果
+     */
+    public static <T> BigDecimal bigDecimalAdd(List<T> list, Function<T, BigDecimal> mapper) {
+        return list.stream().map(mapper).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
+    }
+
+}

+ 5 - 0
sd-business/src/main/resources/mapper/excel/ExcelGenerateLogMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.sd.business.mapper.excel.ExcelGenerateLogMapper">
+
+</mapper>

+ 11 - 0
sd-business/src/main/resources/mapper/order/OrderInfoMapper.xml

@@ -2,4 +2,15 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.sd.business.mapper.order.OrderInfoMapper">
 
+    <select id="getOrderClassifyTotalCount"
+            resultType="com.sd.business.entity.statement.vo.StatementOrderClassifyTotalCountVo">
+        select sum(case when o.classify = 1 then 1 else 0 end) as wlnOrderCount,
+               sum(case when o.classify = 2 then 1 else 0 end) as purchaseOrderCount,
+               sum(case when o.classify = 3 then 1 else 0 end) as outsourceOrderCount,
+               sum(case when o.classify = 4 then 1 else 0 end) as afterSaleOrderCount,
+               sum(case when o.classify = 5 then 1 else 0 end) as noReasonOrderCount
+        from order_info o
+            ${ew.customSqlSegment}
+    </select>
+
 </mapper>

BIN
sd-starter/src/main/resources/template/bomDocument.xlsx


BIN
sd-starter/src/main/resources/template/orderDocument.xlsx


BIN
sd-starter/src/main/resources/template/salesOutWarehouseDetails.xlsx


BIN
sd-starter/src/main/resources/template/skuDocument.xlsx