Merge pull request 'develop' (#193) from develop into master

Reviewed-on: http://git.xdadan.loc/tanex/emis-service/pulls/193
This commit is contained in:
heyu 2025-09-29 14:04:46 +08:00
commit 92661c4c67
14 changed files with 1350 additions and 54 deletions

View File

@ -0,0 +1,107 @@
package com.xdadan.erp.web.emis;
import com.xdadan.erp.common.annotation.Log;
import com.xdadan.erp.common.core.controller.BaseController;
import com.xdadan.erp.common.core.page.TableDataInfo;
import com.xdadan.erp.common.enums.BusinessType;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMissStatistics;
import com.xdadan.erp.emis.service.IEmisTmsSiteBatchMissStatisticsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import static com.xdadan.erp.common.utils.PageUtils.startPage;
/**
* 漏组批次统计Controller
*
* @author heyu
* @date 2025-09-27
*/
@RestController
@RequestMapping("/emis/emisTmsSiteBatchMissStatistics")
@Slf4j
public class EmisTmsSiteBatchMissStatisticsController extends BaseController {
@Autowired
private IEmisTmsSiteBatchMissStatisticsService statisticsService;
/**
* 查询漏组批次统计列表
*/
@PreAuthorize("@ss.hasPermi('emis:emisTmsSiteBatchMissStatistics:list')")
@GetMapping("/list")
public TableDataInfo list(EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics) {
try {
startPage();
List<EmisTmsSiteBatchMissStatistics> list = statisticsService
.selectStatisticsList(emisTmsSiteBatchMissStatistics);
return getDataTable(list);
} catch (Exception e) {
log.error("查询漏组批次统计列表失败", e);
TableDataInfo tableDataInfo = getDataTable(new ArrayList<>());
tableDataInfo.setCode(500);
tableDataInfo.setMsg("查询失败:" + e.getMessage());
return tableDataInfo;
}
}
/**
* 导出漏组详细数据(按月份分sheet)
* 优化版本:支持异步处理、流式导出、缓存优化
*/
@PreAuthorize("@ss.hasPermi('emis:emisTmsSiteBatchMissStatistics:exportDetail')")
@Log(title = "漏组详细数据导出", businessType = BusinessType.EXPORT)
@PostMapping("/exportDetail")
public void exportDetail(HttpServletResponse response,
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics) {
try {
// 设置响应头,支持流式传输
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
// 异步流式导出,避免内存溢出
statisticsService.exportDetailDataByMonthStream(response, emisTmsSiteBatchMissStatistics);
} catch (Exception e) {
log.error("导出漏组详细数据失败", e);
try {
// 检查响应是否已经开始
if (!response.isCommitted()) {
response.reset();
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"success\":false,\"message\":\"导出失败:" + e.getMessage() + "\"}");
}
} catch (Exception ex) {
log.error("写入错误信息失败", ex);
}
}
}
/**
* 导出漏组批次统计查询接口数据
*/
@PreAuthorize("@ss.hasPermi('emis:emisTmsSiteBatchMissStatistics:exportStatistics')")
@Log(title = "漏组批次统计导出", businessType = BusinessType.EXPORT)
@PostMapping("/exportStatistics")
public void exportStatistics(HttpServletResponse response,
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics) {
try {
statisticsService.exportStatisticsData(response, emisTmsSiteBatchMissStatistics);
} catch (Exception e) {
log.error("导出漏组批次统计数据失败", e);
try {
response.getWriter().write("导出失败:" + e.getMessage());
} catch (Exception ex) {
log.error("写入错误信息失败", ex);
}
}
}
}

View File

@ -23,16 +23,14 @@ import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
/**
* @ClassName EmisSettleInvoiceRel
* @Description 开票子账单关联表
* @author linfso
* @date 2024-07-21 13:31:27
*/
@Data
public class EmisSettleInvoiceRel extends BaseEntity
{
@Data
public class EmisSettleInvoiceRel extends BaseEntity {
private static final long serialVersionUID = 1L;
/* id */
@ -46,8 +44,10 @@ public class EmisSettleInvoiceRel extends BaseEntity
private String billNo;
/* 申请开票金额 */
private BigDecimal money;
/* 已收金额 */
private BigDecimal recedMoney;
// 扩展参数
// 扩展参数
private EmisWaybill waybillDetail;
}

View File

@ -1,10 +1,10 @@
/**
/**
* @Project: emis
* @Title: EmisSettlePayRel.java
* @author linfso
* @date 2024-07-21 13:31:24
* @Copyright: ShangHai Duta 2022 All rights reserved.
* @version v1.0
* @version v1.0
* @Description: <p> 支付子账单关联表 实体类 </p>
*/
@ -44,6 +44,8 @@ public class EmisSettlePayRel extends BaseEntity
private String billNo;
/* 金额 */
private BigDecimal payMoney;
/* 发票申请序号 */
private String applySeqNo;
// 扩展参数
private EmisWaybill waybillDetail;

View File

@ -0,0 +1,99 @@
package com.xdadan.erp.emis.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 漏组批次信息导出DTO
* 根据实际Excel截图字段设计,专门用于Excel导出
*
* @author heyu
* @date 2025-09-27
*/
@Data
public class EmisTmsSiteBatchMissExport {
@ExcelProperty("运单号")
private String billCode;
@ExcelProperty("稽核时间")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date auditTime;
@ExcelProperty("发货日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date sendDate;
@ExcelProperty("异常提示")
private String missReason;
@ExcelProperty("起始节点")
private String startSiteName;
@ExcelProperty("下一节点")
private String nextSiteName;
@ExcelProperty("寄件网点")
private String sendSiteName;
@ExcelProperty("线路")
private String lineName;
@ExcelProperty("产品类型")
private String productTypeName;
@ExcelProperty("供应商")
private String supplierName;
@ExcelProperty("寄件国")
private String sendCountryName;
@ExcelProperty("目的国")
private String receiveCountryName;
@ExcelProperty("支付方式")
private String paymentType;
@ExcelProperty("件数")
private Integer parcelQty;
@ExcelProperty("实际重量")
private BigDecimal billWeight;
@ExcelProperty("总体积")
private BigDecimal totalVolume;
@ExcelProperty("节点负责")
private String manager;
@ExcelProperty("线路负责")
private String transManager;
@ExcelProperty("是否问题")
private String blIsQuestion;
@ExcelProperty("录单备注")
private String waybillRemark;
@ExcelProperty("目的网点")
private String destinationName;
@ExcelProperty("修改原因")
private String manualRemark;
@ExcelProperty("完成状态")
private String blManual;
@ExcelProperty("销售联系")
private String salesmen;
@ExcelProperty("回款联系")
private String payee;
@ExcelProperty("录入人")
private String registerManName;
}

View File

@ -0,0 +1,36 @@
package com.xdadan.erp.emis.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xdadan.erp.common.core.domain.BaseEntity;
import lombok.Data;
import java.util.Date;
/**
* 漏组批次统计查询结果DTO
*
* @author heyu
* @date 2025-09-27
*/
@Data
public class EmisTmsSiteBatchMissStatistics extends BaseEntity {
/** 起始网点编码 */
private String startSiteCode;
/** 起始网点名称 */
private String startSiteName;
/** 寄件月份(精确到月) */
@JsonFormat(pattern = "yyyy-MM", timezone = "GMT+8")
private Date billMonth;
/** 票数 */
private Integer ticketCount;
/** 开始月份(含),格式:yyyy-MM */
private String startTime;
/** 结束月份(含),格式:yyyy-MM */
private String endTime;
}

View File

@ -0,0 +1,56 @@
package com.xdadan.erp.emis.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 漏组批次统计导出DTO
*
* @author heyu
* @date 2025-09-27
*/
@Data
public class EmisTmsSiteBatchMissStatisticsExport {
@ExcelProperty("始发网点")
private String startSiteName;
@ExcelProperty("汇总票数")
private Integer totalTicketCount;
@ExcelProperty("1月票数")
private Integer januaryCount;
@ExcelProperty("2月票数")
private Integer februaryCount;
@ExcelProperty("3月票数")
private Integer marchCount;
@ExcelProperty("4月票数")
private Integer aprilCount;
@ExcelProperty("5月票数")
private Integer mayCount;
@ExcelProperty("6月票数")
private Integer juneCount;
@ExcelProperty("7月票数")
private Integer julyCount;
@ExcelProperty("8月票数")
private Integer augustCount;
@ExcelProperty("9月票数")
private Integer septemberCount;
@ExcelProperty("10月票数")
private Integer octoberCount;
@ExcelProperty("11月票数")
private Integer novemberCount;
@ExcelProperty("12月票数")
private Integer decemberCount;
}

View File

@ -0,0 +1,54 @@
package com.xdadan.erp.emis.mapper;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMiss;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMissStatistics;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 漏组批次统计Mapper接口
*
* @author heyu
* @date 2025-09-27
*/
public interface EmisTmsSiteBatchMissStatisticsMapper {
/**
* 查询漏组批次统计列表
*
* @param emisTmsSiteBatchMissStatistics 查询条件对象
* @return 统计结果列表
*/
List<EmisTmsSiteBatchMissStatistics> selectStatisticsList(
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics);
/**
* 查询漏组详细数据列表(按月份分组)
*
* @param emisTmsSiteBatchMissStatistics 查询条件
* @return 详细数据列表
*/
List<EmisTmsSiteBatchMiss> selectDetailDataByMonth(EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics);
/**
* 分页查询漏组详细数据列表(按月份分组)- 性能优化版本
*
* @param emisTmsSiteBatchMissStatistics 查询条件
* @param offset 偏移量
* @param limit 限制数量
* @return 详细数据列表
*/
List<EmisTmsSiteBatchMiss> selectDetailDataByMonthWithPaging(
@Param("query") EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics,
@Param("offset") int offset,
@Param("limit") int limit);
/**
* 统计漏组详细数据总数
*
* @param emisTmsSiteBatchMissStatistics 查询条件
* @return 总记录数
*/
long countDetailDataByMonth(EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics);
}

View File

@ -0,0 +1,45 @@
package com.xdadan.erp.emis.service;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMiss;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMissStatistics;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMissStatisticsExport;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 漏组批次统计Service接口
*
* @author heyu
* @date 2025-09-27
*/
public interface IEmisTmsSiteBatchMissStatisticsService {
/**
* 查询漏组批次统计列表
*
* @param emisTmsSiteBatchMissStatistics 查询条件
* @return 统计结果列表
*/
List<EmisTmsSiteBatchMissStatistics> selectStatisticsList(
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics);
/**
* 流式导出漏组详细数据(按月份分sheet)- 性能优化版本
* 支持大数据量导出,避免内存溢出
*
* @param response HTTP响应
* @param emisTmsSiteBatchMissStatistics 查询条件
*/
void exportDetailDataByMonthStream(HttpServletResponse response,
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics);
/**
* 导出漏组批次统计查询接口数据
*
* @param response HTTP响应
* @param emisTmsSiteBatchMissStatistics 查询条件
*/
void exportStatisticsData(HttpServletResponse response,
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics);
}

View File

@ -1,12 +1,12 @@
/**
* @Project: emis
* @Title: EmisSettlePayRecordServiceImpl.java
* @author linfso
* @date 2024-07-21 13:31:24
* @Copyright: ShangHai Duta 2022 All rights reserved.
* @version v1.0
* @Description: <p> 账单收退款记录 实体类 </p>
*/
/**
* @Project: emis
* @Title: EmisSettlePayRecordServiceImpl.java
* @author linfso
* @date 2024-07-21 13:31:24
* @Copyright: ShangHai Duta 2022 All rights reserved.
* @version v1.0
* @Description: <p> 账单收退款记录 实体类 </p>
*/
package com.xdadan.erp.emis.service.impl;
@ -15,8 +15,11 @@ import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -75,6 +78,12 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
@Autowired
private EmisSettlePayInvoiceRelMapper emisSettlePayInvoiceRelMapper;
@Autowired
private EmisSettleSubBillMapper emisSettleSubBillMapper;
@Autowired
private EmisWaybillMapper emisWaybillMapper;
/**
* 查询账单收退款记录
*
@ -82,8 +91,7 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
* @return 账单收退款记录
*/
@Override
public EmisSettlePayRecord selectEmisSettlePayRecordById(Long id)
{
public EmisSettlePayRecord selectEmisSettlePayRecordById(Long id) {
return emisSettlePayRecordMapper.selectEmisSettlePayRecordById(id);
}
@ -446,7 +454,8 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
emisSettlePayRecord.setSettleBillNo(WaybillHelper.formatQueryValue(emisSettlePayRecord.getSettleBillNo()));
// 多账单合并收款
List<String> settleBillNoArr = Arrays.stream(emisSettlePayRecord.getSettleBillNo().split(",")).distinct().collect(Collectors.toList());
List<String> settleBillNoArr = Arrays.stream(emisSettlePayRecord.getSettleBillNo().split(",")).distinct()
.collect(Collectors.toList());
for (int i = 0; i < settleBillNoArr.size(); i++) {
String settleBillNo = settleBillNoArr.get(i);
@ -514,13 +523,17 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
// 插入数据
emisSettlePayRecordMapper.insertEmisSettlePayRecord(emisSettlePayRecord);
// 重新计算账单收款信息
for (int i = 0; i < settleBillNoArr.size(); i++) {
String settleBillNo = settleBillNoArr.get(i);
if (!StringUtils.isEmpty(settleBillNo)) {
emisSettleBillService.reCalcSettleBillPayStatus(settleBillNo);
}
}
// // 重新计算账单收款信息
// for (int i = 0; i < settleBillNoArr.size(); i++) {
// String settleBillNo = settleBillNoArr.get(i);
// if (!StringUtils.isEmpty(settleBillNo)) {
// emisSettleBillService.reCalcSettleBillPayStatus(settleBillNo);
// }
// }
// 处理部分收款逻辑 - 更新各个维度的收款状态
updatePartialPaymentStatus(emisSettlePayRecord, settleBillNoArr);
return 1;
}
@ -661,4 +674,257 @@ public class EmisSettlePayRecordServiceImpl extends EmisBaseService implements I
}
}
/**
* 更新部分收款状态
* 根据emis_settle_sub_bill的已收金额和本次运单的申请金额加起来与运费比较
* 更新emis_settle_sub_bill、emis_waybill的收款状态、已收金额
* 从账单维度更新emis_settle_bill、从发票维度更新emis_settle_invoice_record的对应字段
*
* @param emisSettlePayRecord 收款记录
* @param settleBillNoArr 账单号数组
*/
private void updatePartialPaymentStatus(EmisSettlePayRecord emisSettlePayRecord, List<String> settleBillNoArr) {
try {
// 处理运单收款关联
List<EmisSettlePayRel> payRelList = emisSettlePayRecord.getPayRelList();
if (!CollectionUtils.isEmpty(payRelList)) {
for (EmisSettlePayRel payRel : payRelList) {
updateWaybillPaymentStatus(payRel);
}
}
// 处理发票收款关联
List<EmisSettlePayInvoiceRel> payInvoiceRelList = emisSettlePayRecord.getPayInvoiceRelList();
if (!CollectionUtils.isEmpty(payInvoiceRelList)) {
for (EmisSettlePayInvoiceRel payInvoiceRel : payInvoiceRelList) {
updateInvoicePaymentStatus(payInvoiceRel, payRelList);
}
}
// 处理账单收款状态
for (String settleBillNo : settleBillNoArr) {
if (!StringUtils.isEmpty(settleBillNo)) {
updateSettleBillPaymentStatus(settleBillNo);
}
}
} catch (Exception e) {
log.error("更新部分收款状态失败", e);
throw new RuntimeException("更新收款状态失败:" + e.getMessage());
}
}
/**
* 更新运单收款状态
*
* @param payRel 运单收款关联
*/
private void updateWaybillPaymentStatus(EmisSettlePayRel payRel) {
try {
String billCode = payRel.getBillNo();
if (StringUtils.isEmpty(billCode)) {
return;
}
// 获取子账单信息
List<EmisSettleSubBill> subBillList = emisSettleSubBillMapper.selectSettleSubBillListByBillCode(billCode);
if (CollectionUtils.isEmpty(subBillList)) {
log.warn("未找到运单号 {} 对应的子账单", billCode);
return;
}
// 获取运单信息
EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(billCode);
if (waybill == null) {
log.warn("未找到运单号 {} 对应的运单信息", billCode);
return;
}
// 计算本次收款金额
BigDecimal currentPayMoney = payRel.getPayMoney() != null ? payRel.getPayMoney() : BigDecimal.ZERO;
// 获取唯一的子账单(一个运单只对应一个子账单)
EmisSettleSubBill subBill = subBillList.get(0);
// 获取子账单的已收金额
BigDecimal currentRecedMoney = subBill.getRecedMoney() != null ? subBill.getRecedMoney()
: BigDecimal.ZERO;
// 计算新的已收金额
BigDecimal newRecedMoney = currentRecedMoney.add(currentPayMoney);
// 获取子账单的运费
BigDecimal billFee = subBill.getBillFee() != null ? subBill.getBillFee() : BigDecimal.ZERO;
// 根据已收金额和运费比较,确定收款状态
String paymentStatus;
if (newRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
paymentStatus = "0"; // 未付款
} else if (newRecedMoney.compareTo(billFee) >= 0) {
paymentStatus = "1"; // 已付款
} else {
paymentStatus = "2"; // 部分付款
}
// 更新子账单收款状态和已收金额
EmisSettleSubBill updateSubBill = new EmisSettleSubBill();
updateSubBill.setBillCode(subBill.getBillCode());
updateSubBill.setPaymentStatus(paymentStatus);
updateSubBill.setRecedMoney(newRecedMoney);
emisSettleSubBillMapper.updatePayedStatus(updateSubBill);
// 更新运单收款状态
EmisWaybill updateWaybill = new EmisWaybill();
updateWaybill.setBillCode(billCode);
updateWaybill.setPaymentStatus(paymentStatus);
emisWaybillMapper.updatePayedStatus(updateWaybill);
log.info("更新运单收款状态成功,运单号: {}, 子账单号: {}, 收款状态: {}, 已收金额: {}, 运费: {}",
billCode, subBill.getBillNo(), paymentStatus, newRecedMoney, billFee);
} catch (Exception e) {
log.error("更新运单收款状态失败,运单号: {}", payRel.getBillNo(), e);
throw e;
}
}
/**
* 更新发票收款状态
*
* @param payInvoiceRel 发票收款关联
* @param payRelList 收款关联列表
*/
private void updateInvoicePaymentStatus(EmisSettlePayInvoiceRel payInvoiceRel, List<EmisSettlePayRel> payRelList) {
try {
String applySeqNo = payInvoiceRel.getApplySeqNo();
if (StringUtils.isEmpty(applySeqNo)) {
return;
}
// 获取发票记录
EmisSettleInvoiceRecord invoiceRecord = emisSettleInvoiceRecordMapper
.selectInvoiceRecordByApplySeqNo(applySeqNo);
if (invoiceRecord == null) {
log.warn("未找到申请序号 {} 对应的发票记录", applySeqNo);
return;
}
BigDecimal money = invoiceRecord.getApplyMoney() != null ? invoiceRecord.getApplyMoney()
: BigDecimal.ZERO;
// 获取发票之前的收款金额
BigDecimal previousRecedMoney = invoiceRecord.getRecedMoney() != null ? invoiceRecord.getRecedMoney()
: BigDecimal.ZERO;
// 计算当前收款记录中与该发票相关的运单收款金额(以applySeqNo关联)
BigDecimal currentInvoicePayMoney = calculateCurrentInvoicePayment(applySeqNo, payRelList);
// 计算新的总收款金额 = 之前的收款金额 + 当前收款金额
BigDecimal totalRecedMoney = previousRecedMoney.add(currentInvoicePayMoney);
String paymentStatus;
if (totalRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
paymentStatus = "0"; // 未付款
} else if (totalRecedMoney.compareTo(money) >= 0) {
paymentStatus = "1"; // 已付款
} else {
paymentStatus = "2"; // 部分付款
}
// 更新发票记录收款状态
EmisSettleInvoiceRecord updateInvoiceRecord = new EmisSettleInvoiceRecord();
updateInvoiceRecord.setId(invoiceRecord.getId());
updateInvoiceRecord.setPaymentStatus(paymentStatus);
updateInvoiceRecord.setRecedMoney(totalRecedMoney);
emisSettleInvoiceRecordMapper.updateEmisSettleInvoiceRecord(updateInvoiceRecord);
log.info("更新发票收款状态成功,申请序号: {}, 收款状态: {}, 总收款金额: {}, 当前收款金额: {}, 申请金额: {}",
applySeqNo, paymentStatus, totalRecedMoney, currentInvoicePayMoney, money);
} catch (Exception e) {
log.error("更新发票收款状态失败,申请序号: {}", payInvoiceRel.getApplySeqNo(), e);
throw e;
}
}
/**
* 计算当前收款记录中与该发票相关的运单收款金额(按applySeqNo关联)
*
* @param applySeqNo 发票申请序号
* @param payRelList 当前收款记录中的运单收款列表
* @return 当前收款金额
*/
private BigDecimal calculateCurrentInvoicePayment(String applySeqNo, List<EmisSettlePayRel> payRelList) {
try {
if (StringUtils.isEmpty(applySeqNo) || CollectionUtils.isEmpty(payRelList)) {
return BigDecimal.ZERO;
}
BigDecimal currentPayment = BigDecimal.ZERO;
for (EmisSettlePayRel payRel : payRelList) {
if (applySeqNo.equals(payRel.getApplySeqNo()) && payRel.getPayMoney() != null) {
currentPayment = currentPayment.add(payRel.getPayMoney());
}
}
return currentPayment;
} catch (Exception e) {
log.error("计算当前发票收款金额失败,申请序号: {}", applySeqNo, e);
return BigDecimal.ZERO;
}
}
/**
* 更新账单收款状态
*
* @param settleBillNo 账单号
*/
private void updateSettleBillPaymentStatus(String settleBillNo) {
try {
// 获取账单信息
EmisSettleBill settleBill = emisSettleBillMapper.selectSettleBillBySettleBillNo(settleBillNo);
if (settleBill == null) {
log.warn("未找到账单号 {} 对应的账单信息", settleBillNo);
return;
}
// 获取账单下的所有子账单
List<EmisSettleSubBill> subBillList = emisSettleSubBillMapper.selectSubBillListBySettleBillNo(settleBillNo);
if (CollectionUtils.isEmpty(subBillList)) {
log.warn("账单号 {} 下没有子账单", settleBillNo);
return;
}
// 计算总已收金额
BigDecimal totalRecedMoney = BigDecimal.ZERO;
for (EmisSettleSubBill subBill : subBillList) {
BigDecimal recedMoney = subBill.getRecedMoney() != null ? subBill.getRecedMoney() : BigDecimal.ZERO;
totalRecedMoney = totalRecedMoney.add(recedMoney);
}
// 根据已收金额和应收金额比较,确定收款状态
BigDecimal recMoney = settleBill.getRecMoney() != null ? settleBill.getRecMoney() : BigDecimal.ZERO;
String paymentStatus;
if (totalRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
paymentStatus = "0"; // 未付款
} else if (totalRecedMoney.compareTo(recMoney) >= 0) {
paymentStatus = "1"; // 已付款
} else {
paymentStatus = "2"; // 部分付款
}
// 更新账单收款状态和已收金额
EmisSettleBill updateSettleBill = new EmisSettleBill();
updateSettleBill.setId(settleBill.getId());
updateSettleBill.setPaymentStatus(paymentStatus);
updateSettleBill.setRecedMoney(totalRecedMoney);
emisSettleBillMapper.updateEmisSettleBill(updateSettleBill);
log.info("更新账单收款状态成功,账单号: {}, 收款状态: {}, 已收金额: {}, 应收金额: {}",
settleBillNo, paymentStatus, totalRecedMoney, recMoney);
} catch (Exception e) {
log.error("更新账单收款状态失败,账单号: {}", settleBillNo, e);
throw e;
}
}
}

View File

@ -0,0 +1,449 @@
package com.xdadan.erp.emis.service.impl;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMiss;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMissStatistics;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMissStatisticsExport;
import com.xdadan.erp.emis.domain.EmisTmsSiteBatchMissExport;
import com.xdadan.erp.emis.mapper.EmisTmsSiteBatchMissStatisticsMapper;
import com.xdadan.erp.emis.service.IEmisTmsSiteBatchMissStatisticsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
* 漏组批次统计Service业务层处理
*
* @author heyu
* @date 2025-09-27
*/
@Service
@Slf4j
public class EmisTmsSiteBatchMissStatisticsServiceImpl implements IEmisTmsSiteBatchMissStatisticsService {
@Autowired
private EmisTmsSiteBatchMissStatisticsMapper statisticsMapper;
// 重用SimpleDateFormat对象,避免重复创建
private static final SimpleDateFormat MONTH_FORMAT = new SimpleDateFormat("yyyy-MM");
private static final SimpleDateFormat MONTH_ONLY_FORMAT = new SimpleDateFormat("MM");
/**
* 查询漏组批次统计列表
*/
@Override
public List<EmisTmsSiteBatchMissStatistics> selectStatisticsList(
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics) {
log.info("查询漏组批次统计列表,startSiteCode: {}, billMonth: {}",
emisTmsSiteBatchMissStatistics.getStartSiteCode(), emisTmsSiteBatchMissStatistics.getBillMonth());
List<EmisTmsSiteBatchMissStatistics> result = statisticsMapper
.selectStatisticsList(emisTmsSiteBatchMissStatistics);
return result;
}
/**
* 导出漏组批次统计查询接口数据
*/
@Override
public void exportStatisticsData(HttpServletResponse response,
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics) {
try {
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("漏组批次统计汇总_" + System.currentTimeMillis(), "UTF-8").replaceAll("\\+",
"%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 查询统计数据
List<EmisTmsSiteBatchMissStatistics> statisticsList = selectStatisticsList(emisTmsSiteBatchMissStatistics);
// 转换为导出格式
List<EmisTmsSiteBatchMissStatisticsExport> exportList = convertToExportFormat(statisticsList);
// 添加合计行
addTotalRow(exportList);
// 导出Excel
EasyExcel.write(response.getOutputStream(), EmisTmsSiteBatchMissStatisticsExport.class)
.sheet("漏组批次统计汇总")
.doWrite(exportList);
} catch (IOException e) {
log.error("导出漏组批次统计数据失败", e);
throw new RuntimeException("导出失败:" + e.getMessage());
}
}
/**
* 转换为导出格式
*/
private List<EmisTmsSiteBatchMissStatisticsExport> convertToExportFormat(
List<EmisTmsSiteBatchMissStatistics> statisticsList) {
// 按起始网点分组,处理null值
Map<String, List<EmisTmsSiteBatchMissStatistics>> groupedBySite = statisticsList.stream()
.filter(Objects::nonNull) // 过滤掉null对象
.collect(Collectors.groupingBy(stat -> {
String siteCode = stat.getStartSiteCode();
return siteCode != null ? siteCode : "未知网点"; // 处理null的startSiteCode
}));
List<EmisTmsSiteBatchMissStatisticsExport> exportList = new ArrayList<>();
for (Map.Entry<String, List<EmisTmsSiteBatchMissStatistics>> entry : groupedBySite.entrySet()) {
String siteCode = entry.getKey();
List<EmisTmsSiteBatchMissStatistics> siteStatistics = entry.getValue();
if (siteStatistics == null || siteStatistics.isEmpty()) {
log.warn("网点 {} 的统计数据为空,跳过处理", siteCode);
continue;
}
EmisTmsSiteBatchMissStatisticsExport export = new EmisTmsSiteBatchMissStatisticsExport();
// 安全获取网点名称,处理null值
String siteName = siteStatistics.get(0).getStartSiteName();
export.setStartSiteName(siteName != null ? siteName : "未知网点");
// 初始化各月份数据
export.setJanuaryCount(0);
export.setFebruaryCount(0);
export.setMarchCount(0);
export.setAprilCount(0);
export.setMayCount(0);
export.setJuneCount(0);
export.setJulyCount(0);
export.setAugustCount(0);
export.setSeptemberCount(0);
export.setOctoberCount(0);
export.setNovemberCount(0);
export.setDecemberCount(0);
int totalCount = 0;
// 填充各月份数据
for (EmisTmsSiteBatchMissStatistics stat : siteStatistics) {
if (stat != null && stat.getBillMonth() != null) {
String month;
synchronized (MONTH_ONLY_FORMAT) {
month = MONTH_ONLY_FORMAT.format(stat.getBillMonth()); // 获取月份部分
}
// 安全获取票数,处理null值
int count = stat.getTicketCount() != null ? stat.getTicketCount() : 0;
totalCount += count;
switch (month) {
case "01":
export.setJanuaryCount(count);
break;
case "02":
export.setFebruaryCount(count);
break;
case "03":
export.setMarchCount(count);
break;
case "04":
export.setAprilCount(count);
break;
case "05":
export.setMayCount(count);
break;
case "06":
export.setJuneCount(count);
break;
case "07":
export.setJulyCount(count);
break;
case "08":
export.setAugustCount(count);
break;
case "09":
export.setSeptemberCount(count);
break;
case "10":
export.setOctoberCount(count);
break;
case "11":
export.setNovemberCount(count);
break;
case "12":
export.setDecemberCount(count);
break;
}
}
}
export.setTotalTicketCount(totalCount);
exportList.add(export);
}
return exportList;
}
/**
* 添加合计行
*/
private void addTotalRow(List<EmisTmsSiteBatchMissStatisticsExport> exportList) {
EmisTmsSiteBatchMissStatisticsExport totalRow = new EmisTmsSiteBatchMissStatisticsExport();
totalRow.setStartSiteName("合计");
totalRow.setTotalTicketCount(0);
totalRow.setJanuaryCount(0);
totalRow.setFebruaryCount(0);
totalRow.setMarchCount(0);
totalRow.setAprilCount(0);
totalRow.setMayCount(0);
totalRow.setJuneCount(0);
totalRow.setJulyCount(0);
totalRow.setAugustCount(0);
totalRow.setSeptemberCount(0);
totalRow.setOctoberCount(0);
totalRow.setNovemberCount(0);
totalRow.setDecemberCount(0);
// 计算合计
for (EmisTmsSiteBatchMissStatisticsExport item : exportList) {
totalRow.setTotalTicketCount(totalRow.getTotalTicketCount() + item.getTotalTicketCount());
totalRow.setJanuaryCount(totalRow.getJanuaryCount() + item.getJanuaryCount());
totalRow.setFebruaryCount(totalRow.getFebruaryCount() + item.getFebruaryCount());
totalRow.setMarchCount(totalRow.getMarchCount() + item.getMarchCount());
totalRow.setAprilCount(totalRow.getAprilCount() + item.getAprilCount());
totalRow.setMayCount(totalRow.getMayCount() + item.getMayCount());
totalRow.setJuneCount(totalRow.getJuneCount() + item.getJuneCount());
totalRow.setJulyCount(totalRow.getJulyCount() + item.getJulyCount());
totalRow.setAugustCount(totalRow.getAugustCount() + item.getAugustCount());
totalRow.setSeptemberCount(totalRow.getSeptemberCount() + item.getSeptemberCount());
totalRow.setOctoberCount(totalRow.getOctoberCount() + item.getOctoberCount());
totalRow.setNovemberCount(totalRow.getNovemberCount() + item.getNovemberCount());
totalRow.setDecemberCount(totalRow.getDecemberCount() + item.getDecemberCount());
}
exportList.add(totalRow);
}
/**
* 流式导出漏组详细数据(按月份分sheet)- 性能优化版本
* 支持大数据量导出,避免内存溢出
*/
@Override
public void exportDetailDataByMonthStream(HttpServletResponse response,
EmisTmsSiteBatchMissStatistics emisTmsSiteBatchMissStatistics) {
long startTime = System.currentTimeMillis();
try {
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("漏组详细数据_" + System.currentTimeMillis(), "UTF-8").replaceAll("\\+",
"%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 先获取总记录数,用于进度跟踪
long totalCount = statisticsMapper.countDetailDataByMonth(emisTmsSiteBatchMissStatistics);
log.info("开始流式导出漏组详细数据,总记录数: {}, 查询条件: {}", totalCount, emisTmsSiteBatchMissStatistics);
if (totalCount == 0) {
// 创建空Excel
EasyExcel.write(response.getOutputStream(), EmisTmsSiteBatchMiss.class)
.sheet("无数据")
.doWrite(new ArrayList<>());
return;
}
// 简化版本:直接查询所有数据并导出,避免复杂的流式处理
// 如果数据量很大,可以考虑分批处理
List<EmisTmsSiteBatchMiss> allData = statisticsMapper
.selectDetailDataByMonth(emisTmsSiteBatchMissStatistics);
log.info("查询到数据条数: {}", allData != null ? allData.size() : 0);
if (allData == null || allData.isEmpty()) {
EasyExcel.write(response.getOutputStream(), EmisTmsSiteBatchMissExport.class)
.sheet("无数据")
.doWrite(new ArrayList<>());
return;
}
// 转换为专门的导出DTO,避免Map类型问题
List<EmisTmsSiteBatchMissExport> exportData = allData.stream()
.filter(Objects::nonNull)
.map(this::convertToExportDto)
.collect(Collectors.toList());
log.info("转换后数据条数: {}", exportData.size());
// 按月份分组数据
Map<String, List<EmisTmsSiteBatchMissExport>> dataByMonth = exportData.stream()
.collect(Collectors.groupingBy(item -> {
if (item.getSendDate() != null) {
synchronized (MONTH_FORMAT) {
return MONTH_FORMAT.format(item.getSendDate());
}
}
return "未知月份";
}));
// 创建Excel写入器
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
// 按月份从小到大排序
List<String> sortedMonths = dataByMonth.keySet().stream()
.filter(month -> !"未知月份".equals(month))
.sorted()
.collect(Collectors.toList());
// 如果有未知月份,放在最后
if (dataByMonth.containsKey("未知月份")) {
sortedMonths.add("未知月份");
}
int sheetIndex = 0;
for (String month : sortedMonths) {
List<EmisTmsSiteBatchMissExport> monthData = dataByMonth.get(month);
if (monthData != null && !monthData.isEmpty()) {
// 创建sheet,使用月份作为sheet名称
String sheetName = month + "月";
WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, sheetName)
.head(EmisTmsSiteBatchMissExport.class)
.build();
// 写入数据
excelWriter.write(monthData, writeSheet);
sheetIndex++;
log.info("写入{}月数据,条数: {}", month, monthData.size());
}
}
// 关闭写入器
excelWriter.finish();
log.info("Excel写入成功,共创建{}个sheet", sheetIndex);
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
log.info("流式导出完成,总处理记录数: {}, 耗时: {}ms, 平均处理速度: {}/s",
allData.size(), duration, allData.size() > 0 ? (allData.size() * 1000 / duration) : 0);
} catch (IOException e) {
long endTime = System.currentTimeMillis();
log.error("流式导出漏组详细数据失败,耗时: {}ms", endTime - startTime, e);
// 不抛出异常,避免重复处理响应
try {
if (!response.isCommitted()) {
response.reset();
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"success\":false,\"message\":\"导出失败:" + e.getMessage() + "\"}");
}
} catch (Exception ex) {
log.error("写入错误响应失败", ex);
}
} catch (Exception e) {
long endTime = System.currentTimeMillis();
log.error("流式导出漏组详细数据发生未知错误,耗时: {}ms", endTime - startTime, e);
try {
if (!response.isCommitted()) {
response.reset();
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"success\":false,\"message\":\"导出失败:" + e.getMessage() + "\"}");
}
} catch (Exception ex) {
log.error("写入错误响应失败", ex);
}
}
}
/**
* 将EmisTmsSiteBatchMiss转换为EmisTmsSiteBatchMissExport用于导出
* 根据实际Excel截图字段进行映射
*/
private EmisTmsSiteBatchMissExport convertToExportDto(EmisTmsSiteBatchMiss miss) {
EmisTmsSiteBatchMissExport export = new EmisTmsSiteBatchMissExport();
// 根据Excel截图字段进行映射
export.setBillCode(miss.getBillCode());
export.setAuditTime(miss.getCreateTime()); // 稽核时间使用创建时间
export.setSendDate(miss.getSendDate());
export.setMissReason(miss.getMissReason());
export.setStartSiteName(miss.getStartSiteName());
export.setNextSiteName(miss.getNextSiteName());
export.setSendSiteName(miss.getSendSiteName());
export.setLineName(miss.getLineName());
export.setProductTypeName(miss.getProductTypeName());
export.setSupplierName(miss.getSupplierName());
export.setSendCountryName(miss.getSendCountryName());
export.setReceiveCountryName(miss.getReceiveCountryName());
export.setPaymentType(convertPaymentType(miss.getPaymentType()));
export.setParcelQty(miss.getParcelQty());
export.setBillWeight(miss.getBillWeight());
export.setTotalVolume(miss.getTotalVolume());
export.setManager(miss.getManager());
export.setTransManager(miss.getTransManager());
export.setBlIsQuestion(convertBlIsQuestion(miss.getBlIsQuestion()));
export.setWaybillRemark(miss.getWaybillRemark());
export.setDestinationName(miss.getDestinationName());
export.setManualRemark(miss.getManualRemark());
export.setBlManual(miss.getBlManual());
export.setSalesmen(miss.getSalesmen());
export.setPayee(miss.getPayee());
export.setRegisterManName(miss.getRegisterManName());
return export;
}
/**
* 转换支付方式
* 根据图2的规则进行转换
*/
private String convertPaymentType(String paymentType) {
if (paymentType == null) {
return "其他";
}
switch (paymentType) {
case "1":
return "现金";
case "2":
return "月结";
case "3":
return "到付";
case "4":
return "到付月结";
case "5":
return "第三方月结";
case "6":
return "其他";
default:
return paymentType; // 如果不在转换范围内,返回原值
}
}
/**
* 转换是否问题件
* 1-是 0-否
*/
private String convertBlIsQuestion(String blIsQuestion) {
if (blIsQuestion == null) {
return "否";
}
if ("1".equals(blIsQuestion)) {
return "是";
} else if ("0".equals(blIsQuestion)) {
return "否";
} else {
return blIsQuestion; // 如果不在转换范围内,返回原值
}
}
}

View File

@ -223,7 +223,7 @@
</select>
<select id="selectInvoiceRecordByApplySeqNo" parameterType="String" resultMap="EmisSettleInvoiceRecordResult">
select id, apply_seq_no, apply_date, apply_man_code, apply_site_code, customer_code, customer_name, settle_bill_no, settle_bill_name, apply_money, invoice_type, company_name, company_tax_no, company_tel, company_address, bank_name, bank_acc_no, contact, phone, real_tax_type, open_money_max, open_money, invoice_no, invoice_status, invoice_status_desc, recieve_address, email, file_path, remark, bl_audit, audit_date, audit_man_code, audit_site_code, audit_note, op_man_code, op_date, op_site_code, open_ch_id, open_ch_status, open_ch_status_desc, open_com_code, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
select id, apply_seq_no, apply_date, apply_man_code, apply_site_code, customer_code, customer_name, settle_bill_no, settle_bill_name, apply_money, invoice_type, company_name, company_tax_no, company_tel, company_address, bank_name, bank_acc_no, contact, phone, real_tax_type, open_money_max, open_money,reced_money, invoice_no, invoice_status, invoice_status_desc, recieve_address, email, file_path, remark, bl_audit, audit_date, audit_man_code, audit_site_code, audit_note, op_man_code, op_date, op_site_code, open_ch_id, open_ch_status, open_ch_status_desc, open_com_code, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_record a
where a.apply_seq_no = #{applySeqNo}
</select>

View File

@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="payId" column="pay_id" />
<result property="billNo" column="bill_no" />
<result property="money" column="money" />
<result property="recedMoney" column="reced_money" />
</resultMap>
<resultMap id="EmisSettleInvoiceRelWithSubBillResult" type="EmisSettleInvoiceRel" extends="EmisSettleInvoiceRelResult" >
@ -21,29 +22,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectEmisSettleInvoiceRelVo">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site from emis_settle_invoice_rel
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(i.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_invoice_record i on r.apply_seq_no = i.apply_seq_no and i.del_flag = '0'
</sql>
<select id="selectEmisSettleInvoiceRelList" parameterType="EmisSettleInvoiceRel" resultMap="EmisSettleInvoiceRelWithSubBillResult">
<include refid="selectEmisSettleInvoiceRelVo"/>
<where>
del_flag='0'
<if test="id != null "> and id = #{id}</if>
<if test="applySeqNo != null and applySeqNo != ''"> and FIND_IN_SET(apply_seq_no, #{applySeqNo} )</if>
<if test="payId != null and payId != ''"> and pay_id=#{payId}</if>
<if test="billNo != null and billNo != ''"> and bill_no like concat('%', #{billNo}, '%')</if>
<if test="money != null "> and money = #{money}</if>
<if test="delFlag != null and delFlag != ''"> and del_flag like concat('%', #{delFlag}, '%')</if>
<if test="createBy != null and createBy != ''"> and create_by like concat('%', #{createBy}, '%')</if>
<if test="createTime != null "> and create_time = #{createTime}</if>
<if test="updateBy != null and updateBy != ''"> and update_by like concat('%', #{updateBy}, '%')</if>
<if test="updateTime != null "> and update_time = #{updateTime}</if>
<if test="createSite != null and createSite != ''"> and create_site like concat('%', #{createSite}, '%')</if>
<if test="updateSite != null and updateSite != ''"> and update_site like concat('%', #{updateSite}, '%')</if>
r.del_flag='0'
<if test="id != null "> and r.id = #{id}</if>
<if test="applySeqNo != null and applySeqNo != ''"> and FIND_IN_SET(r.apply_seq_no, #{applySeqNo} )</if>
<if test="payId != null and payId != ''"> and r.pay_id=#{payId}</if>
<if test="billNo != null and billNo != ''"> and r.bill_no like concat('%', #{billNo}, '%')</if>
<if test="money != null "> and r.money = #{money}</if>
<if test="delFlag != null and delFlag != ''"> and r.del_flag like concat('%', #{delFlag}, '%')</if>
<if test="createBy != null and createBy != ''"> and r.create_by like concat('%', #{createBy}, '%')</if>
<if test="createTime != null "> and r.create_time = #{createTime}</if>
<if test="updateBy != null and updateBy != ''"> and r.update_by like concat('%', #{updateBy}, '%')</if>
<if test="updateTime != null "> and r.update_time = #{updateTime}</if>
<if test="createSite != null and createSite != ''"> and r.create_site like concat('%', #{createSite}, '%')</if>
<if test="updateSite != null and updateSite != ''"> and r.update_site like concat('%', #{updateSite}, '%')</if>
</where>
order by create_time desc
order by r.create_time desc
</select>
<select id="checkUnique" parameterType="EmisSettleInvoiceRel" resultType="int">
@ -66,22 +71,31 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectEmisSettleInvoiceRelById" parameterType="Long" resultMap="EmisSettleInvoiceRelResult">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_rel a
where a.id = #{id}
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(i.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_invoice_record i on r.apply_seq_no = i.apply_seq_no and i.del_flag = '0'
where r.id = #{id}
</select>
<select id="selectListByApplySeqNo" parameterType="String" resultMap="EmisSettleInvoiceRelWithSubBillResult">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_rel a
where a.apply_seq_no = #{applySeqNo} and del_flag='0'
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(i.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_invoice_record i on r.apply_seq_no = i.apply_seq_no and i.del_flag = '0'
where r.apply_seq_no = #{applySeqNo} and r.del_flag='0'
</select>
<select id="selectHasOpenListBySettleBillNo" parameterType="String" resultMap="EmisSettleInvoiceRelWithSubBillResult">
select id, apply_seq_no, pay_id, bill_no, money, del_flag, create_by, create_time, update_by, update_time, create_site, update_site
from emis_settle_invoice_rel a
where del_flag='0'
AND apply_seq_no IN (
select r.id, r.apply_seq_no, r.pay_id, r.bill_no, r.money,
COALESCE(i.reced_money, 0) as reced_money,
r.del_flag, r.create_by, r.create_time, r.update_by, r.update_time, r.create_site, r.update_site
from emis_settle_invoice_rel r
left join emis_settle_invoice_record i on r.apply_seq_no = i.apply_seq_no and i.del_flag = '0'
where r.del_flag='0'
AND r.apply_seq_no IN (
SELECT x1.apply_seq_no FROM
emis_settle_invoice_record x1,
emis_settle_bill x2
@ -91,7 +105,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND FIND_IN_SET( x2.settle_bill_no, x1.settle_bill_no )
AND FIND_IN_SET( x2.settle_bill_no, #{settleBillNo})
)
AND a.bill_no IN (
AND r.bill_no IN (
select essb.bill_no from emis_settle_sub_bill essb where essb.del_flag='0' and FIND_IN_SET( essb.settle_bill_no, #{settleBillNo})
)
</select>

View File

@ -640,7 +640,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="getBillAmountsByPayIds" parameterType="java.util.List" resultType="map">
select
espbr.pay_id,
esb.rec_money
SUM(COALESCE(esb.rec_money, 0)) as rec_money
from emis_settle_pay_bill_rel espbr
left join emis_settle_bill esb on espbr.settle_bill_no = esb.settle_bill_no
where espbr.del_flag = '0' and esb.del_flag = '0'

View File

@ -0,0 +1,168 @@
<?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.xdadan.erp.emis.mapper.EmisTmsSiteBatchMissStatisticsMapper">
<resultMap type="EmisTmsSiteBatchMissStatistics" id="EmisTmsSiteBatchMissStatisticsResult">
<result property="startSiteCode" column="start_site_code"/>
<result property="startSiteName" column="start_site_name"/>
<result property="billMonth" column="bill_month"/>
<result property="ticketCount" column="ticket_count"/>
</resultMap>
<select id="selectStatisticsList" parameterType="EmisTmsSiteBatchMissStatistics" resultMap="EmisTmsSiteBatchMissStatisticsResult">
SELECT
bm.start_site_code,
s.site_name as start_site_name,
STR_TO_DATE(CONCAT(DATE_FORMAT(w.send_date, '%Y-%m'), '-01'), '%Y-%m-%d') as bill_month,
COUNT(*) as ticket_count
FROM emis_tms_site_batch_miss bm
LEFT JOIN emis_waybill w ON bm.bill_code = w.bill_code
LEFT JOIN emis_site s ON bm.start_site_code = s.site_code
WHERE 1=1
<if test="startSiteCode != null and startSiteCode != ''">
AND bm.start_site_code = #{startSiteCode}
</if>
<if test="startTime != null and startTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ >= ]]> #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ <= ]]> #{endTime}
</if>
<if test="(startTime == null or startTime == '') and (endTime == null or endTime == '')">
<if test="billMonth != null">
AND DATE_FORMAT(w.send_date, '%Y-%m') = DATE_FORMAT(#{billMonth}, '%Y-%m')
</if>
</if>
GROUP BY bm.start_site_code, s.site_name, DATE_FORMAT(w.send_date, '%Y-%m')
ORDER BY w.send_date,bm.start_site_code
</select>
<select id="selectDetailDataByMonth" parameterType="EmisTmsSiteBatchMiss" resultMap="com.xdadan.erp.emis.mapper.EmisTmsSiteBatchMissMapper.EmisTmsSiteBatchMissResult">
select
m.id, m.bill_code, m.miss_reason, m.create_time, m.update_time, m.remark, m.del_flag,
m.line_code, m.product_type, m.start_site_code, m.next_site_code, m.supplier_code, m.start_date, m.end_date,m.miss_type,
w.send_site_code, s1.site_name as send_site_name,s2.site_name as start_site_name,s3.site_name as next_site_name, w.send_country, c1.name as send_country_name, w.destination_code, s4.site_name as dispatch_underling_site_name,w.bl_is_question,
l.line_name as line_name,
w.receive_country, c2.name as receive_country_name, w.send_date, w.bl_sign, w.sign_date,
w.product_type,w.problem_type,w.virtual_remark,w.dispatch_underling_site_code,
w.payment_type, w.parcel_qty, w.bill_weight, w.total_volume, w.volume_weight,
w.settlement_weight, w.freight, w.remark as waybill_remark, w.fee_remark, m.manager, k.trans_manager,
w.payee, w.salesmen, u.emp_name as registerManName,
(SELECT s.name
FROM emis_supplier s
WHERE FIND_IN_SET(s.code, m.supplier_code)
AND s.del_flag = '0'
LIMIT 1) as supplier_name,
(SELECT p.prod_name
FROM emis_trans_product p
WHERE FIND_IN_SET(p.prod_code, m.product_type)
AND p.del_flag = '0'
LIMIT 1) as product_type_name
from emis_tms_site_batch_miss m
left join emis_waybill w on m.bill_code = w.bill_code and w.del_flag='0'
left join emis_site s1 on w.send_site_code=s1.site_code and s1.del_flag=0
left join emis_site s2 on m.start_site_code=s2.site_code and s2.del_flag=0
left join emis_site s3 on m.next_site_code=s3.site_code and s3.del_flag=0
left join emis_country c1 on w.send_country=c1.code and c1.del_flag='0'
left join emis_country c2 on w.receive_country=c2.code and c2.del_flag='0'
left join emis_site s4 on w.dispatch_underling_site_code=s4.site_code and s4.del_flag=0
left join emis_trans_line k on w.trans_line_type=k.line_code and k.del_flag='0'
left join emis_trans_plan_rule r on m.trans_plan_rule_id=r.id and r.del_flag='0'
left join emis_trans_line l on m.line_code=l.line_code and l.del_flag='0'
left join sys_user u on w.register_man_code=u.emp_code and u.del_flag='0'
WHERE m.del_flag = '0'
<if test="startSiteCode != null and startSiteCode != ''">
AND m.start_site_code = #{startSiteCode}
</if>
<if test="startTime != null and startTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ >= ]]> #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ <= ]]> #{endTime}
</if>
<if test="(startTime == null or startTime == '') and (endTime == null or endTime == '')">
<if test="billMonth != null">
AND DATE_FORMAT(w.send_date, '%Y-%m') = DATE_FORMAT(#{billMonth}, '%Y-%m')
</if>
</if>
ORDER BY w.send_date DESC, m.bill_code
</select>
<!-- 分页查询漏组详细数据列表(按月份分组)- 性能优化版本 -->
<select id="selectDetailDataByMonthWithPaging" resultMap="com.xdadan.erp.emis.mapper.EmisTmsSiteBatchMissMapper.EmisTmsSiteBatchMissResult">
select
m.id, m.bill_code, m.miss_reason, m.create_time, m.update_time, m.remark, m.del_flag,
m.line_code, m.product_type, m.start_site_code, m.next_site_code, m.supplier_code, m.start_date, m.end_date,m.miss_type,
w.send_site_code, s1.site_name as send_site_name,s2.site_name as start_site_name,s3.site_name as next_site_name, w.send_country, c1.name as send_country_name, w.destination_code, s4.site_name as dispatch_underling_site_name,w.bl_is_question,
l.line_name as line_name,
w.receive_country, c2.name as receive_country_name, w.send_date, w.bl_sign, w.sign_date,
w.product_type,w.problem_type,w.virtual_remark,w.dispatch_underling_site_code,
w.payment_type, w.parcel_qty, w.bill_weight, w.total_volume, w.volume_weight,
w.settlement_weight, w.freight, w.remark as waybill_remark, w.fee_remark, m.manager, k.trans_manager,
w.payee, w.salesmen, u.emp_name as registerManName,
(SELECT s.name
FROM emis_supplier s
WHERE FIND_IN_SET(s.code, m.supplier_code)
AND s.del_flag = '0'
LIMIT 1) as supplier_name,
(SELECT p.prod_name
FROM emis_trans_product p
WHERE FIND_IN_SET(p.prod_code, m.product_type)
AND p.del_flag = '0'
LIMIT 1) as product_type_name
from emis_tms_site_batch_miss m
left join emis_waybill w on m.bill_code = w.bill_code and w.del_flag='0'
left join emis_site s1 on w.send_site_code=s1.site_code and s1.del_flag=0
left join emis_site s2 on m.start_site_code=s2.site_code and s2.del_flag=0
left join emis_site s3 on m.next_site_code=s3.site_code and s3.del_flag=0
left join emis_country c1 on w.send_country=c1.code and c1.del_flag='0'
left join emis_country c2 on w.receive_country=c2.code and c2.del_flag='0'
left join emis_site s4 on w.dispatch_underling_site_code=s4.site_code and s4.del_flag=0
left join emis_trans_line k on w.trans_line_type=k.line_code and k.del_flag='0'
left join emis_trans_plan_rule r on m.trans_plan_rule_id=r.id and r.del_flag='0'
left join emis_trans_line l on m.line_code=l.line_code and l.del_flag='0'
left join sys_user u on w.register_man_code=u.emp_code and u.del_flag='0'
WHERE m.del_flag = '0'
<if test="query.startSiteCode != null and query.startSiteCode != ''">
AND m.start_site_code = #{query.startSiteCode}
</if>
<if test="query.startTime != null and query.startTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ >= ]]> #{query.startTime}
</if>
<if test="query.endTime != null and query.endTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ <= ]]> #{query.endTime}
</if>
<if test="(query.startTime == null or query.startTime == '') and (query.endTime == null or query.endTime == '')">
<if test="query.billMonth != null">
AND DATE_FORMAT(w.send_date, '%Y-%m') = DATE_FORMAT(#{query.billMonth}, '%Y-%m')
</if>
</if>
ORDER BY w.send_date DESC, m.bill_code
LIMIT #{offset}, #{limit}
</select>
<!-- 统计漏组详细数据总数 -->
<select id="countDetailDataByMonth" parameterType="EmisTmsSiteBatchMissStatistics" resultType="long">
SELECT COUNT(*)
FROM emis_tms_site_batch_miss m
LEFT JOIN emis_waybill w ON m.bill_code = w.bill_code AND w.del_flag='0'
WHERE m.del_flag = '0'
<if test="startSiteCode != null and startSiteCode != ''">
AND m.start_site_code = #{startSiteCode}
</if>
<if test="startTime != null and startTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ >= ]]> #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND DATE_FORMAT(w.send_date, '%Y-%m') <![CDATA[ <= ]]> #{endTime}
</if>
<if test="(startTime == null or startTime == '') and (endTime == null or endTime == '')">
<if test="billMonth != null">
AND DATE_FORMAT(w.send_date, '%Y-%m') = DATE_FORMAT(#{billMonth}, '%Y-%m')
</if>
</if>
</select>
</mapper>