BMS计费单据审核计费流水周期开始时间和结束时间的生成

This commit is contained in:
秦鸿展
2026-03-02 13:42:36 +08:00
parent 744385db91
commit 8e51377db1
2 changed files with 173 additions and 39 deletions
@@ -147,15 +147,16 @@ public class BusinessDocumentApplicationService {
if (ObjectUtil.isNull(loginUser)) {
throw new DigitalLogisticsException(UserError.TIMEOUT);
}
//先设置组织信息,因为handleDate方法中需要使用topOrganizationId
businessDocumentDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
businessDocumentDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
businessDocumentDO.setOrganizationName(loginUser.getUserPo().getOrganizationName());
//校验使用的表单是否必填校验
checkDoucumentType(businessDocumentDO);
//处理数据
handleDate(businessDocumentDO);
businessDocumentDO.setDataSources(2);
businessDocumentDO.setBusinessFlow(OrderSequence.getOrderCode("LS"));
businessDocumentDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
businessDocumentDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
businessDocumentDO.setOrganizationName(loginUser.getUserPo().getOrganizationName());
//调用费用计算,计算费用金额进行保存
CostCalculationDTO costCalculationDTO = new CostCalculationDTO();
costCalculationDTO.setOriginalBusinessNum(businessDocumentDO.getOriginalBusinessNum());
@@ -211,6 +212,13 @@ public class BusinessDocumentApplicationService {
* 处理数据
*/
private void handleDate(BusinessDocumentDO businessDocumentDO) {
//确保topOrganizationId已设置,如果为null则从登录用户获取
if (businessDocumentDO.getTopOrganizationId() == null) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNotNull(loginUser) && loginUser.getUserPo() != null) {
businessDocumentDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
}
}
if(businessDocumentDO.getOrganizationId() != null){
//获取组织信息
AjaxResult ajaxResult = productServiceFeign.getOrganizationInfo(businessDocumentDO.getOrganizationId());
@@ -222,11 +230,23 @@ public class BusinessDocumentApplicationService {
throw new ServiceException("组织信息未找到");
}
businessDocumentDO.setOrganizationName(organizationPo.getOrganizationName());
businessDocumentDO.setTopOrganizationId(organizationPo.getParentOrganizationId());
if(organizationPo.getParentOrganizationId()==0){
Long parentOrganizationId = organizationPo.getParentOrganizationId();
if(parentOrganizationId != null && parentOrganizationId != 0){
businessDocumentDO.setTopOrganizationId(parentOrganizationId);
} else {
//如果parentOrganizationId为null或0,使用organizationId作为topOrganizationId
businessDocumentDO.setTopOrganizationId(businessDocumentDO.getOrganizationId());
}
}
//再次确保topOrganizationId不为null(在设置组织信息后)
if (businessDocumentDO.getTopOrganizationId() == null) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNotNull(loginUser) && loginUser.getUserPo() != null) {
businessDocumentDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
} else {
throw new ServiceException("topOrganizationId不能为空,请确保已登录或传入有效的组织信息");
}
}
if(StringUtils.isNotEmpty(businessDocumentDO.getProjectCode())){
AjaxResult ajaxResult = systemServiceFeign.getProjectByCode(businessDocumentDO.getProjectCode());
if(!"200".equals(String.valueOf(ajaxResult.get("code")))) {
@@ -304,7 +324,18 @@ public class BusinessDocumentApplicationService {
}
//根据费用科目code查询费用信息,并赋值
if(StringUtils.isNotEmpty(businessDocumentDO.getSecondSubjectCode())){
AjaxResult ajaxResult = systemServiceFeign.getSubInfoByCode2(businessDocumentDO.getSecondSubjectCode(),businessDocumentDO.getTopOrganizationId());
//确保topOrganizationId不为null,如果为null则从登录用户获取
Long topOrganizationId = businessDocumentDO.getTopOrganizationId();
if (topOrganizationId == null) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNotNull(loginUser) && loginUser.getUserPo() != null) {
topOrganizationId = loginUser.getUserPo().getTopOrganizationId();
businessDocumentDO.setTopOrganizationId(topOrganizationId);
} else {
throw new ServiceException("topOrganizationId不能为空");
}
}
AjaxResult ajaxResult = systemServiceFeign.getSubInfoByCode2(businessDocumentDO.getSecondSubjectCode(), topOrganizationId);
if("200".equals(String.valueOf(ajaxResult.get("code")))){
ExpenseAccountPO expenseAccountPO = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), ExpenseAccountPO.class);
if(null == expenseAccountPO || expenseAccountPO.getExpenseAccountId()==null){
@@ -361,6 +392,19 @@ public class BusinessDocumentApplicationService {
if(businessDocumentPO.getDataSources()==1){
throw new ServiceException("非手工录入数据,无法修改");
}
//确保组织信息已设置,因为handleDate方法中需要使用topOrganizationId
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNotNull(loginUser) && loginUser.getUserPo() != null) {
if (businessDocumentDO.getTopOrganizationId() == null) {
businessDocumentDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
}
if (businessDocumentDO.getOrganizationId() == null) {
businessDocumentDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
}
if (StringUtils.isEmpty(businessDocumentDO.getOrganizationName())) {
businessDocumentDO.setOrganizationName(loginUser.getUserPo().getOrganizationName());
}
}
//校验使用的表单是否必填校验
checkDoucumentType(businessDocumentDO);
//处理数据
@@ -371,7 +371,15 @@ public class BillingStatementDomainService {
String[] ignroreFields = new String[]{"billingStatementId","dataSources","createBy","createByName","createTime","updateBy","updateByName","updateTime"};
BeanUtils.copyProperties(businessDocumentPO,billingStatementDO,ignroreFields);
billingStatementDO.setBusinessDocumentId(businessDocumentPO.getBusinessDocumentId());
billingStatementDO.setBusinessDate(businessDocumentPO.getCreateTime());
//设置业务日期:优先使用计费时间,如果没有则使用创建时间,如果还没有则使用当前日期
Date businessDate = businessDocumentPO.getBillingTime();
if (businessDate == null) {
businessDate = businessDocumentPO.getCreateTime();
}
if (businessDate == null) {
businessDate = new Date();
}
billingStatementDO.setBusinessDate(businessDate);
billingStatementDO.setBillingAmount(businessDocumentPO.getBillAmount());
billingStatementDO.setBillingState(1);
billingStatementDO.setDataSources(1);
@@ -394,6 +402,7 @@ public class BillingStatementDomainService {
private void handleData(BillingStatementDO billingStatementDO) {
//查询合同信息,赋值合同周期信息
//优先通过合同编号获取合同信息
boolean cycleTimeSet = false;
if(StringUtils.isNotEmpty(billingStatementDO.getContractNumber())){
AjaxResult ajaxResult = systemServiceFeign.getInfoByCode(billingStatementDO.getContractNumber());
if("200".equals(String.valueOf(ajaxResult.get("code")))){
@@ -402,7 +411,44 @@ public class BillingStatementDomainService {
//根据合同判断计费流水的周期开始日期和周期结束日期
setCycleTimeByContract(billingStatementDO, contractManagePO);
billingStatementDO.setContractType(contractManagePO.getContractType());
//检查周期时间是否已设置
if(billingStatementDO.getCycleBeginTime() != null && billingStatementDO.getCycleEndTime() != null){
cycleTimeSet = true;
log.info("根据合同设置周期时间成功,合同编号:{},出账日:{},周期开始:{},周期结束:{}",
billingStatementDO.getContractNumber(),
contractManagePO.getPaymentDate(),
billingStatementDO.getCycleBeginTime(),
billingStatementDO.getCycleEndTime());
} else {
log.warn("根据合同设置周期时间失败,合同编号:{},出账日:{}",
billingStatementDO.getContractNumber(),
contractManagePO.getPaymentDate());
}
} else {
log.warn("合同信息为空,合同编号:{}", billingStatementDO.getContractNumber());
}
} else {
log.warn("查询合同信息失败,合同编号:{},返回码:{}",
billingStatementDO.getContractNumber(),
ajaxResult.get("code"));
}
} else {
log.warn("合同编号为空,无法查询合同信息");
}
//如果周期时间未设置,使用业务日期作为默认值
if(!cycleTimeSet){
Date businessDate = billingStatementDO.getBusinessDate();
if(businessDate != null){
billingStatementDO.setCycleBeginTime(businessDate);
billingStatementDO.setCycleEndTime(businessDate);
log.warn("周期时间未设置,使用业务日期作为默认值:{}", businessDate);
} else {
//如果业务日期也为null,使用当前日期
Date now = new Date();
billingStatementDO.setBusinessDate(now);
billingStatementDO.setCycleBeginTime(now);
billingStatementDO.setCycleEndTime(now);
log.warn("业务日期为空,使用当前日期作为默认值:{}", now);
}
}
//根据结算对象获取收支类型
@@ -420,47 +466,91 @@ public class BillingStatementDomainService {
/**
* 根据合同判断计费流水的周期开始日期和周期结束日期
* (1)周期开始日期:根据合同明细的计费属性判断
* - 实时计费、按天计费:周期开始日期 = 业务日期
* - 按账期计费:周期开始日期 = 业务日期
* - 按周计费:周期开始日期 = 业务日期
* (2)周期结束日期:根据合同明细的计费属性判断
* - 实时计费、按天计费:周期结束日期 = 业务日期
* - 按账期计费:周期结束日期 = 合同的出账日期(paymentDate
* - 按周计费:周期结束日期 = 业务日期往后推一周
* 统一使用出账日来计算周期时间:
* 1)周期开始日期:上个月的出账日
* 2)周期结束日期:本月出账日的前一天
* 例如:出账日是10号,业务日期是3月15号,则周期为2月10号到3月9号
* @param billingStatementDO 计费流水对象
* @param contractManagePO 合同管理对象
*/
private void setCycleTimeByContract(BillingStatementDO billingStatementDO, ContractManagePO contractManagePO) {
//取值合同详情,对比费用科目,取值计费周期
if(contractManagePO.getContractManageDetailPOList()!=null && contractManagePO.getContractManageDetailPOList().size()>0){
List<ContractManageDetailPO> contractManageDetailPOList = contractManagePO.getContractManageDetailPOList();
String subjectCode = !StringUtils.isNotEmpty(billingStatementDO.getSecondSubjectCode()) ? billingStatementDO.getFirstSubjectCode() : billingStatementDO.getSecondSubjectCode();
Date cycleBeginTime = null;
Date cycleEndTime = null;
for (ContractManageDetailPO contractManageDetailPO : contractManageDetailPOList) {
String subjectCodeContract = !StringUtils.isNotEmpty(contractManageDetailPO.getSecondSubjectCode()) ? contractManageDetailPO.getFirstSubjectCode() : contractManageDetailPO.getSecondSubjectCode();
if(subjectCodeContract.equals(subjectCode)){
Date businessDate = billingStatementDO.getBusinessDate();
//根据不同类型获取计费周期
if(ObjectUtil.equal(contractManageDetailPO.getBillingAttributesCode(),"1") || ObjectUtil.equal(contractManageDetailPO.getBillingAttributesCode(),"4")){
//实时计费、按天计费,赋值为当天
cycleBeginTime = businessDate;
cycleEndTime = businessDate;
}else if(ObjectUtil.equal(contractManageDetailPO.getBillingAttributesCode(),"2")){
//按账期计费
cycleBeginTime = businessDate;
cycleEndTime = contractManagePO.getPaymentDate();
}else if(ObjectUtil.equal(contractManageDetailPO.getBillingAttributesCode(),"3")){
//按周计费,用businessDate往后推一周的日期
cycleBeginTime = businessDate;
cycleEndTime = DateUtil.offsetWeek(businessDate,1);
Date businessDate = billingStatementDO.getBusinessDate();
//确保业务日期不为null
if (businessDate == null) {
businessDate = new Date();
billingStatementDO.setBusinessDate(businessDate);
log.warn("业务日期为空,使用当前日期:{}", businessDate);
}
//统一根据出账日计算周期时间:开始时间为上个月的出账日,结束时间为本月出账日的前一天
Date paymentDate = contractManagePO.getPaymentDate();
if (paymentDate != null) {
// 获取出账日的"日"部分(1-31
// 注意:由于ContractManagePO中paymentDate的@JsonFormat设置为"d"(只显示日),
// 在反序列化时可能被解析为1970年1月1日,需要特殊处理
int paymentDay;
// 检查是否是1970年1月1日(说明存储的实际上是"日"而不是完整日期)
if (DateUtil.year(paymentDate) == 1970 && DateUtil.month(paymentDate) == 0) {
// 这种情况下,需要从时间戳中提取天数
// 如果数据库中存储的是"10"(表示10号),时间戳可能是10毫秒
long timeInMillis = paymentDate.getTime();
// 如果时间戳很小(小于一天的毫秒数),说明存储的就是天数
if (timeInMillis > 0 && timeInMillis < 24 * 60 * 60 * 1000) {
// 时间戳就是天数(比如10表示10号)
paymentDay = (int)timeInMillis;
} else {
// 否则尝试从日期中提取天数(如果是1970-01-11,则提取11
paymentDay = DateUtil.dayOfMonth(paymentDate);
// 如果提取的是1(1970-01-01),尝试从时间戳计算天数
if (paymentDay == 1) {
// 计算从1970-01-01 00:00:00 UTC开始的天数
long daysFrom1970 = timeInMillis / (24 * 60 * 60 * 1000);
if (daysFrom1970 >= 1 && daysFrom1970 <= 31) {
paymentDay = (int)daysFrom1970;
} else {
// 尝试计算从1970-01-01 00:00:00 CST开始的天数
// 1970-01-01 00:00:00 CST = 1970-01-01 08:00:00 UTC = -28800000毫秒
long cstBaseTime = -8 * 60 * 60 * 1000L; // CST基准时间
long daysFromCST = (timeInMillis - cstBaseTime) / (24 * 60 * 60 * 1000);
if (daysFromCST >= 1 && daysFromCST <= 31) {
paymentDay = (int)daysFromCST;
}
}
}
break;
}
log.info("检测到1970年日期,从时间戳提取出账日:时间戳={},从日期提取={},最终出账日={}",
timeInMillis, DateUtil.dayOfMonth(paymentDate), paymentDay);
} else {
// 正常情况,从日期中提取"日"部分
paymentDay = DateUtil.dayOfMonth(paymentDate);
}
// 确保paymentDay在有效范围内(1-31
if (paymentDay < 1 || paymentDay > 31) {
log.warn("出账日无效:{},使用业务日期的日作为默认值", paymentDay);
paymentDay = DateUtil.dayOfMonth(businessDate);
}
// 使用业务日期来计算周期时间,而不是当前日期
// 计算业务日期所在月的出账日
Date currentMonthPaymentDate = DateUtil.beginOfMonth(businessDate);
currentMonthPaymentDate = DateUtil.offsetDay(currentMonthPaymentDate, paymentDay - 1);
// 结束时间:本月出账日的前一天
Date cycleEndTime = DateUtil.offsetDay(currentMonthPaymentDate, -1);
// 开始时间:上个月的出账日
Date cycleBeginTime = DateUtil.offsetMonth(currentMonthPaymentDate, -1);
billingStatementDO.setCycleBeginTime(cycleBeginTime);
billingStatementDO.setCycleEndTime(cycleEndTime);
log.info("计算周期时间 - 业务日期:{},出账日原始值:{},出账日(日):{},本月出账日:{},周期开始:{},周期结束:{}",
businessDate, paymentDate, paymentDay, currentMonthPaymentDate, cycleBeginTime, cycleEndTime);
} else {
// 如果没有出账日,使用业务日期作为默认值
billingStatementDO.setCycleBeginTime(businessDate);
billingStatementDO.setCycleEndTime(businessDate);
log.warn("合同出账日为空,使用业务日期作为默认值:{}", businessDate);
}
}