bms2相关修改;

This commit is contained in:
王奎兴
2026-03-18 17:41:08 +08:00
parent b0c85db265
commit 347c3dc4c7
36 changed files with 593 additions and 21 deletions
@@ -545,4 +545,4 @@ public class LeaseApplicationService {
// }
// leaseDO.setContainerTypeName(storageTypeDictData.getDictLabel());
// }
}
}
@@ -90,4 +90,7 @@ public class Lease extends BaseVOEntity{
@ApiModelProperty("结算币种")
private String settlementCurrency;
}
@ApiModelProperty("推送时间")
private String pushTime;
}
@@ -91,4 +91,7 @@ public class LeasePO extends BaseVOEntity{
@ApiModelProperty("结算币种")
private String settlementCurrency;
}
@ApiModelProperty("推送时间")
private String pushTime;
}
@@ -107,4 +107,7 @@ public class LeaseDO extends BaseVOEntity{
@ApiModelProperty(name = "修改时间查询条件结束日期")
private String updateTimeEnd;
}
@ApiModelProperty("推送时间")
private String pushTime;
}
@@ -0,0 +1,59 @@
package com.mhd.basic.domain.scheduledTask.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import com.mhd.common.core.web.domain.BaseVOEntity;
import lombok.Data;
import java.time.LocalTime;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
/**
*
* @author gen
* @date 2024-06-07
*/
@Data
public class ScheduledTask extends BaseVOEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("id")
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty("类型")
private String taskType;
@ApiModelProperty("参数")
private String taskData;
@ApiModelProperty("业务id")
private Long busId;
@ApiModelProperty("任务状态")
private String taskStatus;
@ApiModelProperty("")
private Integer retryCount;
@ApiModelProperty("计划执行时间")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date executeTime;
@ApiModelProperty(name = "出账日")
private Integer billDays;
@ApiModelProperty("出账时间")
@JsonFormat(timezone = "GMT+8", pattern = "HH:mm:ss")
@DateTimeFormat(pattern = "HH:mm:ss")
private LocalTime billTime;
@ApiModelProperty("推送时间")
private String pushTime;
}
@@ -0,0 +1,25 @@
package com.mhd.basic.domain.scheduledTask.repository.facade;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mhd.basic.domain.scheduledTask.entity.ScheduledTask;
import com.mhd.basic.domain.lease.entity.Lease;
import java.time.LocalDateTime;
public interface ScheduledTaskService extends IService<ScheduledTask> {
public void saveBillingTask(LocalDateTime billingTime, Lease lease);
/**
* 执行出账
* @param busId 出账数据
* @return 出账结果
*/
void executeBilling(Long busId);
//推送散租到bms
public void ScatteredRentalSynchronization(Long busId);
//推送整租到bms
public void wholeRentSynchronization(Long busId);
}
@@ -0,0 +1,58 @@
package com.mhd.basic.domain.scheduledTask.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mhd.basic.domain.scheduledTask.entity.ScheduledTask;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.time.LocalDateTime;
import java.util.List;
public interface ScheduledTaskMapper extends BaseMapper<ScheduledTask> {
/**
* 查询待执行的任务
* @param startTime 开始时间
* @param endTime 结束时间
* @param status 任务状态
* @param limit 限制条数
* @return 任务列表
*/
List<ScheduledTask> findPendingTasks(
@Param("startTime") LocalDateTime startTime,
@Param("endTime") LocalDateTime endTime,
@Param("status") String status,
@Param("limit") Integer limit);
/**
* 通过乐观锁更新任务状态
* @param id 任务ID
* @param oldStatus 旧状态
* @param newStatus 新状态
* @return 更新的记录数
*/
@Update("UPDATE scheduled_task SET task_status = #{newStatus}, update_time = NOW() " +
"WHERE id = #{id} AND task_status = #{oldStatus}")
int updateStatusIfPending(
@Param("id") Long id,
@Param("oldStatus") String oldStatus,
@Param("newStatus") String newStatus);
/**
* 更新任务状态
* @param id 任务ID
* @param status 新状态
* @return 更新的记录数
*/
@Update("UPDATE scheduled_task SET task_status = #{status}, update_time = NOW() " +
"WHERE id = #{id}")
int updateStatus(@Param("id") Long id, @Param("status") String status);
/**
* 增加重试次数
* @param id 任务ID
* @return 更新的记录数
*/
@Update("UPDATE scheduled_task SET retry_count = retry_count + 1, update_time = NOW() " +
"WHERE id = #{id}")
int incrementRetryCount(@Param("id") Long id);
}
@@ -0,0 +1,162 @@
package com.mhd.basic.domain.scheduledTask.repository.persistence;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mhd.basic.application.service.Lease.LeaseApplicationService;
import com.mhd.basic.domain.scheduledTask.entity.ScheduledTask;
import com.mhd.basic.domain.scheduledTask.repository.facade.ScheduledTaskService;
import com.mhd.basic.domain.scheduledTask.repository.mapper.ScheduledTaskMapper;
import com.mhd.basic.domain.lease.entity.Lease;
import com.mhd.basic.domain.lease.repository.facade.ILeaseService;
import com.mhd.basic.domain.lease.repository.po.LeasePO;
import com.mhd.basic.domain.lease.repository.todo.LeaseDO;
import com.mhd.common.core.domain.dto.BusinessDataPushDTO;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.system.api.BmsServiceFeign;
import com.mhd.system.api.WmsServiceFeign;
import com.mhd.system.api.domain.MaterialInventoryDTO;
import com.mhd.system.api.domain.MaterialInventoryPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Objects;
@Slf4j
@Service
public class ScheduledTaskServiceImpl extends ServiceImpl<ScheduledTaskMapper, ScheduledTask> implements ScheduledTaskService {
@Resource
private ScheduledTaskMapper taskMapper;
@Resource
private ObjectMapper objectMapper;
@Resource
private BmsServiceFeign bmsServiceFeign;
@Resource
private WmsServiceFeign WmsServiceFeign;
@Resource
private LeaseApplicationService leaseApplicationService;
@Resource
private ILeaseService leaseService;
public void saveBillingTask(LocalDateTime billingTime, Lease lease) {
ScheduledTask task = new ScheduledTask();
task.setTaskType("LeaseToBms");
task.setExecuteTime(Date.from(billingTime.atZone(ZoneId.systemDefault()).toInstant()));
task.setTaskData(JSON.toJSONString(lease));
task.setBusId(lease.getId());
task.setTaskStatus("PENDING");
taskMapper.insert(task);
}
@Override
public void executeBilling(Long busId) {
try {
log.info("开始执行出账业务");
LeasePO leasePO = leaseService.getInfo(busId);
String leaseType = leasePO.getLeaseType();
if ("整租".equals(leaseType)) {
wholeRentSynchronization(busId);
} else if ("散租".equals(leaseType)) {
ScatteredRentalSynchronization(busId);
}
} catch (Exception e) {
log.error("出账业务异常", e);
}
}
/**
* 定时任务整租推送到bms
*/
public void wholeRentSynchronization(Long busId) {
log.info("定时任务整租推送到bms触发--开始");
LeaseDO leaseDO = new LeaseDO();
leaseDO.setTime(new Date());
leaseDO.setLeaseType("整租");
leaseDO.setId(busId);
List<LeasePO> leasePOList = leaseApplicationService.queryList(leaseDO);
log.info("整租数据{}", JSONObject.toJSONString(leasePOList));
for (LeasePO leasePO: leasePOList) {
if (leasePO.getShipperId() == null) {
continue;
}
log.info("开始执行{}",JSONObject.toJSONString(leasePOList));
BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO();
businessDataPushDTO.setOrganizationId(leasePO.getOrganizationId());
businessDataPushDTO.setTopOrganizationId(leasePO.getTopOrganizationId());
businessDataPushDTO.setOrganizationName(leasePO.getOrganizationName());
businessDataPushDTO.setBelongModuleCode("wms");
// businessDataPushDTO.setBillAmount();//计费金额
JSONObject jsonObject = new JSONObject();
jsonObject.put("lease_area",leasePO.getLeaseArea());//租赁面积
jsonObject.put("jiecun_cbm",0);//结存体积
businessDataPushDTO.setDocumentFormJson(jsonObject.toJSONString());
businessDataPushDTO.setDocumentTypeCode("TY_ZL");
businessDataPushDTO.setSettlementEntityId(leasePO.getShipperId());
businessDataPushDTO.setSecondSubjectCode(leasePO.getSecondSubjectCode());
businessDataPushDTO.setServiceItemsCode(leasePO.getServiceItemsCode());
businessDataPushDTO.setDataSources(1);
bmsServiceFeign.businessDocumentApiSave(businessDataPushDTO);
}
log.info("定时任务整租推送到bms触发--结束");
}
/**
* 定时任务散租推送到bms
*/
public void ScatteredRentalSynchronization(Long busId) {
LeaseDO leaseDO = new LeaseDO();
leaseDO.setTime(new Date());
leaseDO.setLeaseType("散租");
leaseDO.setId(busId);
List<LeasePO> leasePOList = leaseApplicationService.queryList(leaseDO);
for (LeasePO leasePO: leasePOList) {
if (leasePO.getShipperId() == null) {
continue;
}
MaterialInventoryDTO materialInventoryDTO = new MaterialInventoryDTO();
materialInventoryDTO.setShipperId(leasePO.getShipperId());
BigDecimal totalVolume = BigDecimal.ZERO;
AjaxResult ajaxResult = WmsServiceFeign.materialInventoryApiListAll(materialInventoryDTO);
if (ajaxResult != null && "200".equals(String.valueOf(ajaxResult.get("code")))) {
List<MaterialInventoryPO> batchDetailFeignPOList = JSON.parseArray(
com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), MaterialInventoryPO.class);
totalVolume = batchDetailFeignPOList.stream()
.map(MaterialInventoryPO::getVolume)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO();
businessDataPushDTO.setOrganizationId(leasePO.getOrganizationId());
businessDataPushDTO.setTopOrganizationId(leasePO.getTopOrganizationId());
businessDataPushDTO.setOrganizationName(leasePO.getOrganizationName());
businessDataPushDTO.setBelongModuleCode("wms");
// businessDataPushDTO.setBillAmount();//计费金额
JSONObject jsonObject = new JSONObject();
jsonObject.put("lease_area",0);//租赁面积
jsonObject.put("jiecun_cbm",totalVolume);//结存体积
businessDataPushDTO.setDocumentFormJson(jsonObject.toJSONString());
businessDataPushDTO.setDocumentTypeCode("TY_ZL");
businessDataPushDTO.setSettlementEntityId(leasePO.getShipperId());
businessDataPushDTO.setSecondSubjectCode(leasePO.getSecondSubjectCode());
businessDataPushDTO.setServiceItemsCode(leasePO.getServiceItemsCode());
businessDataPushDTO.setDataSources(1);
bmsServiceFeign.businessDocumentApiSave(businessDataPushDTO);
}
}
}
@@ -0,0 +1,69 @@
package com.mhd.basic.domain.scheduledTask.repository.task;
import com.mhd.basic.domain.scheduledTask.entity.ScheduledTask;
import com.mhd.basic.domain.scheduledTask.repository.facade.ScheduledTaskService;
import com.mhd.basic.domain.scheduledTask.repository.mapper.ScheduledTaskMapper;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class BillingScheduler {
@Resource
private ScheduledTaskMapper scheduledTaskMapper;
@Resource
private ScheduledTaskService scheduledTaskService;
// 每10秒扫描一次
//@Scheduled(fixedDelay = 10000)
@Transactional
public void scanAndExecute() {
// 查询当前时间前1分钟内待执行的任务
LocalDateTime now = LocalDateTime.now();
LocalDateTime start = now.minusMinutes(1);
List<ScheduledTask> tasks = scheduledTaskMapper.findPendingTasks(
start, now, "PENDING", 100);
for (ScheduledTask task : tasks) {
try {
// 乐观锁更新状态,防止重复执行
int updated = scheduledTaskMapper.updateStatusIfPending(
task.getId(), "PENDING", "PROCESSING");
if (updated > 0) {
// 异步执行具体业务
CompletableFuture.runAsync(() -> {
executeTask(task);
});
}
} catch (Exception e) {
scheduledTaskMapper.updateStatus(task.getId(), "FAILED");
}
}
}
private void executeTask(ScheduledTask task) {
try {
// 执行具体的出账逻辑
scheduledTaskService.executeBilling(task.getBusId());
scheduledTaskMapper.updateStatus(task.getId(), "SUCCESS");
} catch (Exception e) {
// 重试机制
scheduledTaskMapper.incrementRetryCount(task.getId());
if (task.getRetryCount() < 3) {
scheduledTaskMapper.updateStatus(task.getId(), "PENDING");
} else {
scheduledTaskMapper.updateStatus(task.getId(), "FAILED");
}
}
}
}
@@ -104,4 +104,7 @@ public class LeaseDTO extends BaseVOEntity{
@ApiModelProperty(name = "修改时间查询条件结束日期")
private String updateTimeEnd;
}
@ApiModelProperty("推送时间")
private String pushTime;
}
@@ -0,0 +1,73 @@
<?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.mhd.basic.domain.scheduledTask.repository.mapper.ScheduledTaskMapper">
<!-- 通用结果映射 -->
<resultMap id="BaseResultMap" type="com.mhd.basic.domain.scheduledTask.entity.ScheduledTask">
<id column="id" property="id"/>
<result column="task_type" property="taskType"/>
<result column="execute_time" property="executeTime"/>
<result column="task_data" property="taskData"/>
<result column="task_status" property="taskStatus"/>
<result column="retry_count" property="retryCount"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<!-- 通用查询列 -->
<sql id="Base_Column_List">
id, task_type, execute_time, task_data, task_status, retry_count, create_time, update_time, bill_days, bill_time,bus_id
</sql>
<!-- 查询待执行任务 -->
<select id="findPendingTasks" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM scheduled_task
WHERE
TO_DATE(
TO_CHAR(SYSDATE, 'YYYY-MM-') || PUSH_TIME,
'YYYY-MM-DD HH24:MI:SS'
) BETWEEN #{startTime} AND #{endTime}
and task_status = #{status}
ORDER BY TO_DATE(
TO_CHAR(SYSDATE, 'YYYY-MM-') || PUSH_TIME,
'YYYY-MM-DD HH24:MI:SS'
) ASC
LIMIT #{limit}
</select>
<!-- 批量更新状态(可选:用于批量处理) -->
<update id="batchUpdateStatus" parameterType="map">
UPDATE scheduled_task
SET task_status = #{newStatus},
update_time = NOW()
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
AND task_status = #{oldStatus}
</update>
<!-- 统计待处理任务数量 -->
<select id="countPendingTasks" resultType="int">
SELECT COUNT(*)
FROM scheduled_task
WHERE task_status = 'PENDING'
AND execute_time &lt;= NOW()
</select>
<!-- 查询超时任务(处理中超过30分钟的任务) -->
<select id="findTimeoutTasks" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM scheduled_task
WHERE
task_status = 'PROCESSING'
AND update_time &lt; DATE_SUB(NOW(), INTERVAL 30 MINUTE)
LIMIT 50
</select>
</mapper>