diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleBillController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleBillController.java index a5d82b36a..db4abe2d1 100644 --- a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleBillController.java +++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleBillController.java @@ -714,63 +714,104 @@ public class EmisSettleBillController extends BaseController { try { - EmisSettleBill bill=emisBaseService.getSettleBillBySettleBillNo(emisSettleBill.getSettleBillNo()); + // 参数校验 + if (emisSettleBill == null || StringUtils.isEmpty(emisSettleBill.getSettleBillNo())) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + EmisSettleBill bill = emisBaseService.getSettleBillBySettleBillNo(emisSettleBill.getSettleBillNo()); + // 账单不存在校验 + if (bill == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + // 获取子账单数据 List list = emisBaseService.selectSubBillListBySettleBillNo(emisSettleBill.getSettleBillNo()); + // 子账单列表为空校验 + if (CollectionUtils.isEmpty(list)) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + // 转换子账单为 MAP - Map textMap = MapUtils.newHashMap(); - textMap.put("title", bill.getSettleBillName()); - textMap.put("total", bill.getRecMoney().stripTrailingZeros().toPlainString()); + textMap.put("title", bill.getSettleBillName() != null ? bill.getSettleBillName() : ""); + // 处理可能为null的金额 + BigDecimal recMoney = bill.getRecMoney(); + textMap.put("total", recMoney != null ? recMoney.stripTrailingZeros().toPlainString() : "0"); - String tplName="tpl/bill_tpl_simple.xlsx"; + String tplName = "tpl/bill_tpl_simple.xlsx"; // 是否使用复复杂模版,如果有清关费用和其他费用都需要使用复杂模版 - boolean isNeedComplexTpl=false; + boolean isNeedComplexTpl = false; + + List> listMap = new ArrayList<>(); + for (EmisSettleSubBill billItem : list) { + // 跳过waybillDetail为null的项 + if (billItem == null || billItem.getWaybillDetail() == null) { + continue; + } - List> listMap=new ArrayList<>(); - for(EmisSettleSubBill billItem:list){ Map voMap = new HashMap<>(); - voMap.put("sendDate", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,billItem.getWaybillDetail().getSendDate())) ; - voMap.put("billCode",billItem.getBillCode()); - voMap.put("fjr",billItem.getWaybillDetail().getSendName()+"--"+billItem.getWaybillDetail().getReceiveName()); - voMap.put("kjlx",billItem.getWaybillDetail().getSendSiteName()+"--"+billItem.getWaybillDetail().getDispatchUnderlingSiteName()); + // 安全处理日期 + Date sendDate = billItem.getWaybillDetail().getSendDate(); + voMap.put("sendDate", sendDate != null ? DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, sendDate) : ""); + + voMap.put("billCode", billItem.getBillCode() != null ? billItem.getBillCode() : ""); - String company=billItem.getWaybillDetail().getCustName(); - if( - "1".equals(billItem.getWaybillDetail().getPaymentType()) || - "3".equals(billItem.getWaybillDetail().getPaymentType()) || - "5".equals(billItem.getWaybillDetail().getPaymentType()) + // 安全处理字符串拼接 + String sendName = billItem.getWaybillDetail().getSendName() != null ? billItem.getWaybillDetail().getSendName() : ""; + String receiveName = billItem.getWaybillDetail().getReceiveName() != null ? billItem.getWaybillDetail().getReceiveName() : ""; + voMap.put("fjr", sendName + "--" + receiveName); - ){ - company=billItem.getWaybillDetail().getSendCompany(); + String sendSiteName = billItem.getWaybillDetail().getSendSiteName() != null ? billItem.getWaybillDetail().getSendSiteName() : ""; + String dispatchUnderlingSiteName = billItem.getWaybillDetail().getDispatchUnderlingSiteName() != null ? billItem.getWaybillDetail().getDispatchUnderlingSiteName() : ""; + voMap.put("kjlx", sendSiteName + "--" + dispatchUnderlingSiteName); + + String company = billItem.getWaybillDetail().getCustName() != null ? billItem.getWaybillDetail().getCustName() : ""; + String paymentType = billItem.getWaybillDetail().getPaymentType(); + if ("1".equals(paymentType) || "3".equals(paymentType) || "5".equals(paymentType)) { + String sendCompany = billItem.getWaybillDetail().getSendCompany(); + company = sendCompany != null ? sendCompany : ""; } - voMap.put("company",company); - voMap.put("paymentType", DictUtils.getDictLabel("emis_payment_type",billItem.getWaybillDetail().getPaymentType())); - voMap.put("productTypeName", billItem.getWaybillDetail().getProductTypeName()); - voMap.put("parcelQty", billItem.getWaybillDetail().getParcelQty().toString()); - voMap.put("billWeight", billItem.getWaybillDetail().getBillWeight().stripTrailingZeros().toPlainString()); - voMap.put("settlementWeight", billItem.getWaybillDetail().getSettlementWeight().stripTrailingZeros().toPlainString()); - voMap.put("totalVolume", billItem.getWaybillDetail().getTotalVolume().stripTrailingZeros().toPlainString()); - voMap.put("freight", billItem.getWaybillDetail().getFreight().stripTrailingZeros().toPlainString()); + voMap.put("company", company); + voMap.put("paymentType", DictUtils.getDictLabel("emis_payment_type", paymentType)); + + String productTypeName = billItem.getWaybillDetail().getProductTypeName(); + voMap.put("productTypeName", productTypeName != null ? productTypeName : ""); - String feeRemark=""; - if(!StringUtils.isEmpty(billItem.getWaybillDetail().getFeeRemark())){ - feeRemark=billItem.getWaybillDetail().getFeeRemark(); + // 安全处理Integer转String + Integer parcelQty = billItem.getWaybillDetail().getParcelQty(); + voMap.put("parcelQty", parcelQty != null ? parcelQty.toString() : "0"); + + // 安全处理BigDecimal + BigDecimal billWeight = billItem.getWaybillDetail().getBillWeight(); + voMap.put("billWeight", billWeight != null ? billWeight.stripTrailingZeros().toPlainString() : "0"); + + BigDecimal settlementWeight = billItem.getWaybillDetail().getSettlementWeight(); + voMap.put("settlementWeight", settlementWeight != null ? settlementWeight.stripTrailingZeros().toPlainString() : "0"); + + BigDecimal totalVolume = billItem.getWaybillDetail().getTotalVolume(); + voMap.put("totalVolume", totalVolume != null ? totalVolume.stripTrailingZeros().toPlainString() : "0"); + + BigDecimal freight = billItem.getWaybillDetail().getFreight(); + voMap.put("freight", freight != null ? freight.stripTrailingZeros().toPlainString() : "0"); + + String feeRemark = ""; + String feeRemarkValue = billItem.getWaybillDetail().getFeeRemark(); + if (!StringUtils.isEmpty(feeRemarkValue)) { + feeRemark = feeRemarkValue; } - String waybillRemark=""; - if(!StringUtils.isEmpty(billItem.getWaybillDetail().getRemark())){ - waybillRemark=billItem.getWaybillDetail().getRemark(); + String waybillRemark = ""; + String remarkValue = billItem.getWaybillDetail().getRemark(); + if (!StringUtils.isEmpty(remarkValue)) { + waybillRemark = remarkValue; } -// if(!StringUtils.isEmpty(billItem.getWaybillDetail().getFeeRemark())){ -// feeRemark=feeRemark+" "+billItem.getWaybillDetail().getFeeRemark(); -// } - - - BigDecimal otherFee = BigDecimal.ZERO; BigDecimal transFee = BigDecimal.ZERO; BigDecimal cebFee = BigDecimal.ZERO; @@ -780,150 +821,167 @@ public class EmisSettleBillController extends BaseController String declareFeeStr = ""; String otherFeeStr = ""; - String feeItemRemark=""; + String feeItemRemark = ""; - //计算分项数据 - List feeItemList=billItem.getFeeitemList(); - if( !CollectionUtils.isEmpty(feeItemList)){ + // 计算分项数据 + List feeItemList = billItem.getFeeitemList(); + if (!CollectionUtils.isEmpty(feeItemList)) { for (EmisSettleSubBillFeeitem feeitem : feeItemList) { - - // 所有币种全部统一换算成RMB - - BigDecimal rmbBillFee=feeitem.getBillFee(); - // 币种 - String currencyStr=""; - if(StringUtils.isEmpty(feeitem.getCurrency())){ - feeitem.setCurrency("CNY"); + if (feeitem == null) { + continue; } - if(!"CNY".equals(feeitem.getCurrency())){ - currencyStr=""+feeitem.getCurrency()+""; - // 非人民币需要换算成人民币 - EmisExchangeRate emisExchangeRate=emisExchangeRateService.getValidExchangeRate(currencyStr,"CNY",DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,billItem.getWaybillDetail().getSendDate())); - double rate=0.0D; - if(emisExchangeRate!=null){ - rate=Double.valueOf(emisExchangeRate.getRate()); - rmbBillFee=rmbBillFee.multiply(BigDecimal.valueOf(rate)); - } + // 所有币种全部统一换算成RMB + BigDecimal billFee = feeitem.getBillFee(); + if (billFee == null) { + billFee = BigDecimal.ZERO; + } + BigDecimal rmbBillFee = billFee; + + // 币种 + String currencyStr = ""; + String currency = feeitem.getCurrency(); + if (StringUtils.isEmpty(currency)) { + feeitem.setCurrency("CNY"); + currency = "CNY"; + } + if (!"CNY".equals(currency)) { + currencyStr = currency; + // 非人民币需要换算成人民币 + if (sendDate != null) { + String dateStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, sendDate); + EmisExchangeRate emisExchangeRate = emisExchangeRateService.getValidExchangeRate(currencyStr, "CNY", dateStr); + if (emisExchangeRate != null && emisExchangeRate.getRate() != null) { + try { + double rate = Double.parseDouble(emisExchangeRate.getRate()); + rmbBillFee = rmbBillFee.multiply(BigDecimal.valueOf(rate)); + } catch (NumberFormatException e) { + // 汇率转换失败,使用原值 + logger.warn("汇率转换失败,币种: {}, 汇率: {}", currencyStr, emisExchangeRate.getRate()); + } + } + } } // 费用细分 - if ("1001".equals(feeitem.getFeeCode())) { + String feeCode = feeitem.getFeeCode(); + if ("1001".equals(feeCode)) { transFee = transFee.add(rmbBillFee); -// transFeeStr= feeitem.getBillFee().stripTrailingZeros().toPlainString()+currencyStr; } // 报关费 - else if ("2002".equals(feeitem.getFeeCode())) { + else if ("2002".equals(feeCode)) { cebFee = cebFee.add(rmbBillFee); -// cebFeeStr= feeitem.getBillFee().stripTrailingZeros().toPlainString()+currencyStr; } // 清关费 - else if ("2003".equals(feeitem.getFeeCode())) { + else if ("2003".equals(feeCode)) { declareFee = declareFee.add(rmbBillFee); -// declareFeeStr= feeitem.getBillFee().stripTrailingZeros().toPlainString()+currencyStr; -// - } else { otherFee = otherFee.add(rmbBillFee); -// otherFeeStr= otherFeeStr+""+feeitem.getFeeName()+":"+feeitem.getBillFee().stripTrailingZeros().toPlainString()+currencyStr+","; -// } - - if( - cebFee.compareTo(BigDecimal.ZERO)>0 - || declareFee.compareTo(BigDecimal.ZERO)>0 - || otherFee.compareTo(BigDecimal.ZERO)>0 - ){ - isNeedComplexTpl=true; + if (cebFee.compareTo(BigDecimal.ZERO) > 0 + || declareFee.compareTo(BigDecimal.ZERO) > 0 + || otherFee.compareTo(BigDecimal.ZERO) > 0) { + isNeedComplexTpl = true; } - if(!StringUtils.isEmpty(feeitem.getRemark())){ - if(!feeitem.getRemark().contains("w")){ - feeItemRemark=feeItemRemark+"|"+feeitem.getFeeName()+":"+feeitem.getBillFee().stripTrailingZeros().toPlainString()+currencyStr+"(费用说明:"+feeitem.getRemark()+")"; + String feeItemRemarkValue = feeitem.getRemark(); + if (!StringUtils.isEmpty(feeItemRemarkValue)) { + if (!feeItemRemarkValue.contains("w")) { + String feeName = feeitem.getFeeName() != null ? feeitem.getFeeName() : ""; + String billFeeStr = billFee.stripTrailingZeros().toPlainString(); + feeItemRemark = feeItemRemark + "|" + feeName + ":" + billFeeStr + currencyStr + "(费用说明:" + feeItemRemarkValue + ")"; } } - } - transFeeStr= transFee.stripTrailingZeros().toPlainString(); - cebFeeStr= cebFee.stripTrailingZeros().toPlainString(); - declareFeeStr= declareFee.stripTrailingZeros().toPlainString(); - otherFeeStr= otherFee.stripTrailingZeros().toPlainString(); - }else{ - transFeeStr=billItem.getWaybillDetail().getFreight().stripTrailingZeros().toPlainString(); + transFeeStr = transFee.stripTrailingZeros().toPlainString(); + cebFeeStr = cebFee.stripTrailingZeros().toPlainString(); + declareFeeStr = declareFee.stripTrailingZeros().toPlainString(); + otherFeeStr = otherFee.stripTrailingZeros().toPlainString(); + } else { + // 如果没有费用项列表,使用运单的运费 + if (freight != null) { + transFeeStr = freight.stripTrailingZeros().toPlainString(); + } else { + transFeeStr = "0"; + } } - if(StringUtils.isEmpty(transFeeStr)){ - transFeeStr="0"; + if (StringUtils.isEmpty(transFeeStr)) { + transFeeStr = "0"; } - if(StringUtils.isEmpty(cebFeeStr)){ - cebFeeStr="0"; + if (StringUtils.isEmpty(cebFeeStr)) { + cebFeeStr = "0"; } - if(StringUtils.isEmpty(declareFeeStr)){ - declareFeeStr="0"; + if (StringUtils.isEmpty(declareFeeStr)) { + declareFeeStr = "0"; } - if(StringUtils.isEmpty(otherFeeStr)){ - otherFeeStr="0"; + if (StringUtils.isEmpty(otherFeeStr)) { + otherFeeStr = "0"; } - voMap.put("transFee",transFeeStr); - voMap.put("cebFee",cebFeeStr); - voMap.put("declareFee",declareFeeStr); + voMap.put("transFee", transFeeStr); + voMap.put("cebFee", cebFeeStr); + voMap.put("declareFee", declareFeeStr); - otherFeeStr=StringUtils.removeEnd(otherFeeStr,","); + otherFeeStr = StringUtils.removeEnd(otherFeeStr, ","); - voMap.put("otherFee",otherFeeStr); + voMap.put("otherFee", otherFeeStr); - if(!StringUtils.isEmpty(feeItemRemark)){ - feeItemRemark="费用项:"+StringUtils.removeEnd(feeItemRemark,"|"); + if (!StringUtils.isEmpty(feeItemRemark)) { + feeItemRemark = "费用项:" + StringUtils.removeEnd(feeItemRemark, "|"); } -// feeRemark=feeRemark+","+feeItemRemark; - feeRemark=StringUtils.removeEnd(feeRemark,",")+""; + feeRemark = StringUtils.removeEnd(feeRemark, ",") + ""; - voMap.put("feeRemark", feeRemark+" "+waybillRemark); + voMap.put("feeRemark", feeRemark + " " + waybillRemark); listMap.add(voMap); } - - if(isNeedComplexTpl) { + if (isNeedComplexTpl) { tplName = "tpl/bill_tpl.xlsx"; - }else{ + } else { tplName = "tpl/bill_tpl_simple.xlsx"; } ServletOutputStream outputStream = response.getOutputStream(); - //账单主数据填充 - InputStream inputStream = ResourceUtil.getResourceObj(tplName).getStream(); + // 账单主数据填充 + InputStream inputStream = ResourceUtil.getResourceObj(tplName).getStream(); // 设置创建行的方式 FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); -// FillConfig fillConfig2 = FillConfig.builder().forceNewRow(Boolean.FALSE).build(); ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).excelType(ExcelTypeEnum.XLSX).build(); // 写入到sheet WriteSheet sheet0 = EasyExcel.writerSheet(0).build(); excelWriter.fill(textMap, sheet0); // 填充 - logger.error("====>listMap===>{}",JSON.toJSONString(listMap)); + logger.error("====>listMap===>{}", JSON.toJSONString(listMap)); excelWriter.fill(listMap, fillConfig, sheet0); // 设置响应头信息 - String fileName = bill.getSettleBillName()+".xlsx"; + String billName = bill.getSettleBillName(); + String fileName = (billName != null ? billName : "账单") + ".xlsx"; response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())); response.setContentType("application/octet-stream"); - //关流 + // 关流 excelWriter.finish(); IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); } catch (IOException e) { + logger.error("导出账单失败", e); e.printStackTrace(); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } catch (Exception e) { + logger.error("导出账单异常", e); + e.printStackTrace(); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyDetailMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyDetailMapper.java index 53f90239d..6dcff46cd 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyDetailMapper.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyDetailMapper.java @@ -10,9 +10,11 @@ */ package com.xdadan.erp.emis.mapper; +import java.math.BigDecimal; import java.util.List; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xdadan.erp.emis.domain.EmisWriteoffApplyDetail; +import org.apache.ibatis.annotations.Param; /** * @ClassName EmisWriteoffApplyDetailMapper @@ -104,4 +106,14 @@ public interface EmisWriteoffApplyDetailMapper extends BaseMapper + * - 来自 auditCenterPass:申请金额 + 已收金额 <= 账单应收金额 + * - 非 auditCenterPass:申请金额 + 该运单历史申请金额(所有 bl_center_confirmed != 1 的申请明细之和) + 已收金额 <= 账单应收金额 + *

+ * + * @param fromAuditCenterPass 是否来自财务中心审核通过(auditCenterPass) + */ + private void validateWriteoffAmount(EmisWriteoffApply emisWriteoffApply, boolean fromAuditCenterPass) + throws EmisBizError { if (CollectionUtils.isEmpty(emisWriteoffApply.getDetailList())) { throw new EmisBizError("销账申请明细不能为空"); } @@ -170,9 +185,16 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm } // 验证:申请金额 + 已收金额 <= 账单应收金额 - BigDecimal totalAmount = detail.getApplyMoney().add(receivedAmount); + BigDecimal historyApplyAmount = BigDecimal.ZERO; + if (!fromAuditCenterPass) { + BigDecimal dbSum = emisWriteoffApplyDetailMapper.sumHistoryApplyMoneyByBillCode(detail.getBillCode(), + emisWriteoffApply.getId()); + historyApplyAmount = dbSum != null ? dbSum : BigDecimal.ZERO; + } + + BigDecimal totalAmount = detail.getApplyMoney().add(historyApplyAmount).add(receivedAmount); if (totalAmount.compareTo(recMoney) > 0) { - throw new EmisBizError("运单号 " + detail.getBillCode() + " 的申请金额(" + detail.getApplyMoney() + throw new EmisBizError("运单号 " + detail.getBillCode() + " 的累计申请金额(" + detail.getApplyMoney().add(historyApplyAmount) + ") + 已收金额(" + receivedAmount + ") = " + totalAmount + " 超过运单应收金额(" + recMoney + ")"); } @@ -431,8 +453,8 @@ public class EmisWriteoffApplyServiceImpl extends EmisBaseService implements IEm .selectEmisWriteoffApplyDetailListByApplyIdWithDetails(existingApply.getId()); existingApply.setDetailList(detailList); - // 验证销账金额 - validateWriteoffAmount(existingApply); + // 验证销账金额(财务中心审核通过场景不纳入“历史申请金额”) + validateWriteoffAmount(existingApply, true); // 先更新相关业务数据(在更新审核状态之前进行验证和更新) detailList = updateRelatedBusinessData(existingApply, true); diff --git a/emis-biz/src/main/resources/mapper/EmisWriteoffApplyDetailMapper.xml b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyDetailMapper.xml index c1c653a36..15d419ffb 100644 --- a/emis-biz/src/main/resources/mapper/EmisWriteoffApplyDetailMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyDetailMapper.xml @@ -252,6 +252,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" left join emis_site dest_site on w.dispatch_underling_site_code = dest_site.site_code and dest_site.del_flag = '0' + + +