Merge branch 'dev' into dev-bms-0723

# Conflicts:
#	mhd_bms/src/main/resources/bootstrap.yml
#	mhd_bms/src/main/resources/mapper/SettlementCustomersMapper.xml
This commit is contained in:
王奎兴
2026-08-05 18:19:19 +08:00
79 changed files with 2788 additions and 214 deletions
@@ -136,8 +136,12 @@ public class BillManageApplicationService {
List<BillManagePO> billManagePOS = billManageDomainService.queryList(billManageDO);
for (BillManagePO billManagePO : billManagePOS) {
String billNumber = billManagePO.getBillNumber(); // 获取账单编号
// 原有 - 前端列表用,不变
List<BillDetail> billDetails = billDetailMapper.selectList(new LambdaQueryWrapper<BillDetail>().eq(BillDetail::getBillNumber, billNumber));
billManagePO.setBillDetailList(billDetails);
// 新增 - 导出用,LEFT JOIN billing_statement 拿到费用科目
List<BillDetailPO> billDetailPOs = billDetailMapper.getDetailsByBillManageId(billManagePO.getBillManageId());
billManagePO.setBillDetailPOList(billDetailPOs);
}
return billManagePOS;
}
@@ -363,6 +367,19 @@ public class BillManageApplicationService {
billDetailDTO1.setFeeType(billDetailDTO1.getServiceItemsName());
});
}
//同步更新已有计费流水(调整账单时可修改已有费用)
List<BillDetailDTO> billDetailDTOListHasBillingStatementId = billDetailDTOList.stream()
.filter(billDetailDTO -> billDetailDTO.getBillingStatementId() != null)
.collect(Collectors.toList());
for (BillDetailDTO billDetailDTO : billDetailDTOListHasBillingStatementId) {
BillingStatementDO billingStatementDO = new BillingStatementDO();
BeanUtils.copyProperties(billDetailDTO, billingStatementDO);
billingStatementDO.setBillingStatementId(billDetailDTO.getBillingStatementId());
billingStatementDO.setBillManageId(billManagePO.getBillManageId());
billingStatementDO.setBillingState(3);
billingStatementDO.setAccountExpenseType(billDetailDTO.getBillType());
billingStatementApplicationService.update(billingStatementDO);
}
//保存账单明细
Boolean flag = billDetailDomainService.saveBatch(billDetailDTOList);
//更新账单金额
@@ -478,6 +495,19 @@ public class BillManageApplicationService {
item.setFeeType(item.getServiceItemsName());
});
}
//同步更新已有计费流水(新增账单时可修改已有费用)
List<BillDetailDTO> billDetailDTOListHasBillingStatementId = billDetailDTOList.stream()
.filter(item -> item.getBillingStatementId() != null)
.collect(Collectors.toList());
for (BillDetailDTO billDetailDTO : billDetailDTOListHasBillingStatementId) {
BillingStatementDO billingStatementDO = new BillingStatementDO();
BeanUtils.copyProperties(billDetailDTO, billingStatementDO);
billingStatementDO.setBillingStatementId(billDetailDTO.getBillingStatementId());
billingStatementDO.setBillManageId(billManageDO.getBillManageId());
billingStatementDO.setBillingState(3);
billingStatementDO.setAccountExpenseType(billDetailDTO.getBillType());
billingStatementApplicationService.update(billingStatementDO);
}
//保存账单明细
double allTaxRate = 0.0d;
BigDecimal allTaxAmount = BigDecimal.ZERO;
@@ -515,105 +545,51 @@ public class BillManageApplicationService {
}
/**
* 复制账单
* 复制账单-获取原账单数据供前端回显
* 前端拿到数据后跳转到类似修改/新增账单的页面,用户修改后通过addBill接口提交新增
*/
@Transactional
public Boolean copyBill(BillManageDTO billManageDTO) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
throw new DigitalLogisticsException(UserError.TIMEOUT);
}
public BillManagePO copyBill(BillManageDTO billManageDTO) {
if (billManageDTO.getBillManageId() == null) {
throw new ServiceException("原账单id不能为空");
}
// 1. 获取原账单信息
// 获取原账单信息
BillManagePO originalBill = billManageDomainService.getInfo(billManageDTO.getBillManageId());
if (null == originalBill) {
throw new ServiceException("原账单信息未找到");
}
// 2. 获取原账单明细
// 获取原账单明细
List<BillDetailPO> originalDetails = billDetailDomainService.getDetailsByBillManageId(billManageDTO.getBillManageId());
if (originalDetails == null || originalDetails.isEmpty()) {
throw new ServiceException("原账单明细为空,无法复制");
}
// 3. 创建新账单,除账单编号外完全复制原账单
String newBillNumber = OrderSequence.getOrderCode("ZD");
BillManage newBill = new BillManage();
BeanUtils.copyProperties(originalBill, newBill);
newBill.setBillManageId(null);
newBill.setBillNumber(newBillNumber);
newBill.setCreateBy(loginUser.getUserPo().getUserId());
newBill.setCreateByName(loginUser.getUserPo().getUserName());
newBill.setCreateTime(new Date());
newBill.setUpdateBy(loginUser.getUserPo().getUserId());
newBill.setUpdateByName(loginUser.getUserPo().getUserName());
newBill.setUpdateTime(new Date());
newBill.setDelFlag(1);
// 复制后重置状态字段为初始值
// 账单状态、对账状态、发票状态重置
newBill.setBillState(1); // 1-未确认
newBill.setBillStep(1); // 1-发起对账
newBill.setReconciliationStatus(0); // 1-暂未确认
newBill.setIsInvoice(0); // 0-未索取
// 实收=0,未收=账单金额
newBill.setActualReceivedAmount(BigDecimal.ZERO);
newBill.setBillAmountUnsettled(newBill.getBillAmount());
newBill.setBillAmountSettlement(BigDecimal.ZERO);
// NC同步状态重置
newBill.setSynchronousStatus(0); // 0-未同步
newBill.setSkSynchronousStatus(0); // 0-未同步
// 清空发票、收款、推送相关字段
newBill.setApplyNumber(null); // 发票申请单号
newBill.setSettlementTime(null); // 收款时间
newBill.setSynchronousTime(null); // 应收单推送时间
newBill.setSkSynchronousTime(null); // 收款单推送时间
newBill.setInvoiceId(null); // 发票表ID
newBill.setInvoiceMakeTime(null); // 开票时间
newBill.setNcId(null); // nc唯一标识(应收)
newBill.setSkNcId(null); // nc唯一标识(收款)
// 保存新账单
boolean flag = billManageDomainService.saveEntity(newBill);
if (!flag) {
throw new ServiceException("复制账单失败,请重试");
// 重置关键字段为初始值,清空id等,方便前端回显后直接提交新增
originalBill.setBillManageId(null);
originalBill.setBillNumber(null);
originalBill.setBillState(1);
originalBill.setBillStep(1);
originalBill.setReconciliationStatus(0);
originalBill.setIsInvoice(0);
originalBill.setActualReceivedAmount(BigDecimal.ZERO);
originalBill.setBillAmountUnsettled(originalBill.getBillAmount());
originalBill.setBillAmountSettlement(BigDecimal.ZERO);
originalBill.setSynchronousStatus(0);
originalBill.setSkSynchronousStatus(0);
originalBill.setApplyNumber(null);
originalBill.setSettlementTime(null);
originalBill.setSynchronousTime(null);
originalBill.setSkSynchronousTime(null);
originalBill.setInvoiceId(null);
originalBill.setInvoiceMakeTime(null);
originalBill.setNcId(null);
originalBill.setSkNcId(null);
// 明细也清空id
for (BillDetailPO detail : originalDetails) {
detail.setBillDetailId(null);
detail.setBillManageId(null);
detail.setBillNumber(null);
}
// 4. 复制账单明细
List<BillDetail> newDetailList = new ArrayList<>();
for (BillDetailPO originalDetail : originalDetails) {
BillDetail newDetail = new BillDetail();
BeanUtils.copyProperties(originalDetail, newDetail);
newDetail.setBillDetailId(null);
newDetail.setBillManageId(newBill.getBillManageId());
newDetail.setBillNumber(newBillNumber);
newDetail.setCreateBy(loginUser.getUserPo().getUserId());
newDetail.setCreateByName(loginUser.getUserPo().getUserName());
newDetail.setCreateTime(new Date());
newDetailList.add(newDetail);
}
Boolean flagTwo = billDetailDomainService.insertBatch(newDetailList);
// 5. 复制计费流水(billing_statement
List<BillingStatementPO> originalStatements = billingStatementDomainService.getDetailsByManageId(billManageDTO.getBillManageId());
boolean flagThree = true;
if (originalStatements != null && !originalStatements.isEmpty()) {
List<BillingStatement> newStatementList = new ArrayList<>();
for (BillingStatementPO originalStatement : originalStatements) {
BillingStatement newStatement = new BillingStatement();
BeanUtils.copyProperties(originalStatement, newStatement);
newStatement.setBillingStatementId(null);
newStatement.setBillManageId(newBill.getBillManageId());
newStatement.setCreateBy(loginUser.getUserPo().getUserId());
newStatement.setCreateByName(loginUser.getUserPo().getUserName());
newStatement.setCreateTime(new Date());
newStatementList.add(newStatement);
}
flagThree = billingStatementDomainService.saveEntityBatch(newStatementList);
}
// 6. 保存操作日志
BillOperationLogDO billOperationLogDO = new BillOperationLogDO();
billOperationLogDO.setBillManageId(newBill.getBillManageId());
billOperationLogDO.setOperationInfo(StringUtils.format(BillLogsConstants.copy_bill_text, originalBill.getBillNumber(), newBillNumber));
billOperationLogDO.setOperationType(1);
boolean three = billOperationLogDomainService.saveBillOperationLog(billOperationLogDO);
return flag && flagTwo && flagThree && three;
originalBill.setBillDetailPOList(originalDetails);
return originalBill;
}
/**
@@ -0,0 +1,145 @@
package com.mhd.bms.interfaces.dto.billManage;
import com.mhd.common.core.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "应收账单导出对象")
public class BillManageExportVO {
/** ====== 原有账单头字段(与 BillManagePO 的 @Excel 一致) ====== */
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@Excel(name = "组织表ID")
private Long organizationId;
@Excel(name = "组织名称")
private String organizationName;
@Excel(name = "账单编号")
private String billNumber;
@Excel(name = "账单类型", readConverterExp = "1=-应收,2-应付")
private Integer billType;
@Excel(name = "账单状态", readConverterExp = "1=-未确认,2-对账中,3-未收款/付款,4-部分收款/付款,5-已收款/付款,6-已作废,7-已退款")
private Integer billState;
@Excel(name = "账单流程节点", readConverterExp = "1=-发起对账,2-客户确认,3-财务审核,4-收款/付款")
private Integer billStep;
@Excel(name = "系统来源")
private String belongModule;
@Excel(name = "系统来源code")
private String belongModuleCode;
@Excel(name = "结算对象id")
private Long settlementCustomersId;
@Excel(name = "结算对象code")
private String settlementCustomersCode;
@Excel(name = "结算对象")
private String settlementEntity;
@Excel(name = "账单总金额")
private BigDecimal billTotalAmount;
@Excel(name = "优惠金额")
private BigDecimal billDiscountAmount;
@Excel(name = "账单金额")
private BigDecimal billAmount;
@Excel(name = "已收/付金额")
private BigDecimal billAmountSettlement;
@Excel(name = "未收/付金额")
private BigDecimal billAmountUnsettled;
@Excel(name = "期望金额")
private BigDecimal billExpectedAmount;
@Excel(name = "对账状态", readConverterExp = "1=-暂未确认,2-申请调账,3-财务调账,4-核对无误")
private Integer reconciliationStatus;
@Excel(name = "对账意见描述")
private String reconciliationOpinion;
@Excel(name = "客户凭证地址")
private String voucherAddress;
@Excel(name = "财务审核结果(1-同意,2-拒绝)")
private Integer financialReviewFlag;
@Excel(name = "审核意见描述")
private String financialReviewOpinion;
@Excel(name = "周期开始时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date cycleBeginTime;
@Excel(name = "周期结束时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date cycleEndTime;
@Excel(name = "收款/付款时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date settlementTime;
@Excel(name = "备注")
private String billRemark;
@Excel(name = "折扣百分比")
private BigDecimal billDiscount;
@Excel(name = "折扣上限金额")
private BigDecimal billDiscountLimit;
@Excel(name = "费用计算精度code")
private String costAccuracyCode;
@Excel(name = "费用计算精度name")
private String costAccuracyName;
@Excel(name = "尾数计算code")
private String tailCalculationCode;
@Excel(name = "尾数计算name")
private String tailCalculationName;
@Excel(name = "账单金额精度code")
private String amountAccuracyCode;
@Excel(name = "账单金额精度name")
private String amountAccuracyName;
/** ====== 新增明细字段(来源于 bill_detail + billing_statement ====== */
@Excel(name = "费用类别")
private String feeType;
@Excel(name = "费用类型code")
private String serviceItemsCode;
@Excel(name = "费用类型")
private String serviceItemsName;
@Excel(name = "一级费用科目code")
private String firstSubjectCode;
@Excel(name = "一级费用科目")
private String firstSubjectName;
@Excel(name = "二级费用科目code")
private String secondSubjectCode;
@Excel(name = "二级费用科目")
private String secondSubjectName;
@Excel(name = "明细金额")
private BigDecimal billingAmount;
}
@@ -6,6 +6,8 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.io.IOException;
import java.net.URLEncoder;
import com.mhd.bms.application.server.billManage.BillManageApplicationService;
import com.mhd.bms.domain.billManage.repository.po.BillDetailPO;
@@ -13,7 +15,9 @@ import com.mhd.bms.domain.billingStatement.repository.todo.BillingStatementDO;
import com.mhd.bms.domain.ncLog.entity.NcLog;
import com.mhd.bms.infrastructure.utils.UniqueKeyUtil;
import com.mhd.bms.interfaces.dto.billingStatement.BillingStatementDTO;
import com.mhd.bms.interfaces.dto.billManage.BillManageExportVO;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.poi.ExcelUtil;
import com.mhd.common.log.annotation.Log;
import com.mhd.common.log.enums.BusinessType;
import com.mhd.common.redis.enums.RedisLockTypeEnum;
@@ -31,6 +35,7 @@ import com.mhd.bms.domain.billManage.repository.todo.BillManageDO;
import com.mhd.bms.domain.billManage.repository.po.BillManagePO;
import com.mhd.bms.interfaces.assembler.billManage.BillManageAssembler;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import com.mhd.common.core.web.controller.BaseController;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.core.web.page.TableDataInfo;
@@ -79,6 +84,55 @@ public class BillManageApi extends BaseController{
return AjaxResult.success(billManageApplicationService.listCount(billManageDO));
}
@ApiOperation("导出应收账单")
@GetMapping(value = "/exportReceivableList", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public void exportReceivableList(BillManageDTO billManageDTO, HttpServletResponse response) throws IOException
{
//转换实体
BillManageDO billManageDO = new BillManageDO();
BeanUtils.copyProperties(billManageDTO,billManageDO);
billManageDO.setBillType(1);
//查全部(不分页)
List<BillManagePO> list = billManageApplicationService.queryList(billManageDO);
//扁平化处理:一条明细生成一行
List<BillManageExportVO> exportList = new ArrayList<>();
for (BillManagePO bill : list) {
List<BillDetailPO> details = bill.getBillDetailPOList();
if (details != null && !details.isEmpty()) {
for (BillDetailPO detail : details) {
BillManageExportVO vo = new BillManageExportVO();
//复制全部账单头字段
BeanUtils.copyProperties(bill, vo);
//覆盖明细字段
vo.setFeeType(detail.getFeeType());
vo.setServiceItemsCode(detail.getServiceItemsCode());
vo.setServiceItemsName(detail.getServiceItemsName());
vo.setFirstSubjectCode(detail.getFirstSubjectCode());
vo.setFirstSubjectName(detail.getFirstSubjectName());
vo.setSecondSubjectCode(detail.getSecondSubjectCode());
vo.setSecondSubjectName(detail.getSecondSubjectName());
vo.setBillingAmount(detail.getBillingAmount());
exportList.add(vo);
}
} else {
//没有明细也要有一行
BillManageExportVO vo = new BillManageExportVO();
BeanUtils.copyProperties(bill, vo);
exportList.add(vo);
}
}
//设置下载头,防止浏览器乱码
String fileName = URLEncoder.encode("应收账单", "UTF-8").replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
ExcelUtil<BillManageExportVO> util = new ExcelUtil<>(BillManageExportVO.class);
util.exportExcel(response, exportList, "应收账单");
}
@ApiOperation("获取nc推送日志")
@GetMapping(value = "/getNcLog")
public AjaxResult getNcLog(@RequestParam(name = "billManageId") Long billManageId, @RequestParam(name = "type") Long type)
@@ -258,7 +312,7 @@ public class BillManageApi extends BaseController{
}
@ApiOperation("复制账单")
@ApiOperation("复制账单-获取原账单数据用于回显")
@PostMapping("/copyBill")
public AjaxResult copyBill(@RequestBody BillManageDTO billManageDTO)
{
@@ -266,8 +320,8 @@ public class BillManageApi extends BaseController{
throw new ServiceException("原账单id不能为空");
}
try {
Boolean result = billManageApplicationService.copyBill(billManageDTO);
return toAjax(result);
BillManagePO result = billManageApplicationService.copyBill(billManageDTO);
return AjaxResult.success(result);
}catch (Exception e){
return AjaxResult.error("复制账单失败:"+e.getMessage());
}
@@ -166,12 +166,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessDocumentDO.contractName != null and businessDocumentDO.contractName != ''">
AND contract_name like concat('%', #{businessDocumentDO.contractName}, '%')
</if>
<!-- <if test="businessDocumentDO.billAmount != null and businessDocumentDO.billAmount != ''">-->
<!-- AND bill_amount like concat('%', #{businessDocumentDO.billAmount}, '%')-->
<!-- </if>-->
<if test="businessDocumentDO.billAmount != null and businessDocumentDO.billAmount != ''">
AND bill_amount like concat('%', #{businessDocumentDO.billAmount}, '%')
and bill_amount = #{businessDocumentDO.billAmount}
</if>
<if test="businessDocumentDO.estimatedCost != null and businessDocumentDO.estimatedCost != ''">
AND estimated_cost like concat('%', #{businessDocumentDO.estimatedCost}, '%')
AND estimated_cost = #{businessDocumentDO.estimatedCost}
</if>
<!-- <if test="businessDocumentDO.estimatedCost != null and businessDocumentDO.estimatedCost != ''">-->
<!-- AND estimated_cost like concat('%', #{businessDocumentDO.estimatedCost}, '%')-->
<!-- </if>-->
<if test="businessDocumentDO.firstSubjectName != null and businessDocumentDO.firstSubjectName != ''">
AND first_subject_name like concat('%', #{businessDocumentDO.firstSubjectName}, '%')
</if>
@@ -193,6 +199,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessDocumentDO.documentTypeCode != null and businessDocumentDO.documentTypeCode != ''">
AND document_type_code = #{businessDocumentDO.documentTypeCode}
</if>
<if test="businessDocumentDO.salesmanId != null and businessDocumentDO.salesmanId != ''">
AND document_type_code = #{businessDocumentDO.salesmanId}
</if>
<if test="businessDocumentDO.businessDocumentIdSet != null">
and business_document_id in
<foreach item="id" collection="businessDocumentDO.businessDocumentIdSet" open="(" separator="," close=")">