Răsfoiți Sursa

fix: 基础平台服务
1.增加消费明细异常通过界面重新入库并更新异常的重新入库结果

luoyb 8 luni în urmă
părinte
comite
515ea72b3e

+ 10 - 0
ruoyi-api/ruoyi-api-consume/src/main/java/org/dromara/consume/api/RemoteConsumeService.java

@@ -4,8 +4,10 @@ import org.dromara.common.core.domain.R;
 import org.dromara.common.core.domain.model.ErrorInfo;
 import org.dromara.consume.api.domain.bo.RemoteConsumeBo;
 import org.dromara.consume.api.domain.bo.RemoteResultDto;
+import org.dromara.consume.api.domain.bo.RemoteXfExceptionDto;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 /**
  * @ClassName RemoteConsumeService
@@ -77,4 +79,12 @@ public interface RemoteConsumeService {
      * @return 是否成功
      */
     boolean cancleDeal(Long termNo,Integer termRecordId);
+
+    /**
+     * 重新入账消费明细
+     *
+     * @param remoteBos 消费数据
+     * @return 入账结果
+     */
+    List<RemoteXfExceptionDto> rePostConsumeData(List<RemoteXfExceptionDto> remoteBos);
 }

+ 115 - 0
ruoyi-api/ruoyi-api-consume/src/main/java/org/dromara/consume/api/domain/bo/RemoteXfExceptionDto.java

@@ -0,0 +1,115 @@
+package org.dromara.consume.api.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 消费明细异常业务对象 t_xf_exception
+ *
+ * @author LionLi
+ * @date 2025-09-15
+ */
+@Data
+@NoArgsConstructor
+public class RemoteXfExceptionDto implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 8846217223745836309L;
+    /**
+     * 消费明细异常Id,主键
+     */
+    private Long exceptId;
+
+    /**
+     * 卡流水号
+     */
+    @NotNull(message = "卡流水号不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Long cardNo;
+
+    /**
+     * 物理卡号
+     */
+    @NotNull(message = "物理卡号不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Long factoryId;
+
+    /**
+     * 设备机号
+     */
+    @NotNull(message = "设备机号不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Long termNo;
+
+    /**
+     * 机器流水号
+     */
+    @NotNull(message = "机器流水号不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Long termRecordId;
+
+    /**
+     * 对应原始记录表中的record_Id
+     */
+    @NotNull(message = "对应原始记录表中的record_Id不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Long recordId;
+
+    /**
+     * 人员Id
+     */
+    @NotNull(message = "人员Id不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Long userId;
+
+    /**
+     * 学/工号
+     */
+    @NotBlank(message = "学/工号不能为空", groups = {AddGroup.class, EditGroup.class})
+    private String userNumb;
+
+    /**
+     * 用户姓名
+     */
+    @NotBlank(message = "用户姓名不能为空", groups = {AddGroup.class, EditGroup.class})
+    private String realName;
+
+    /**
+     * 消费日期
+     */
+    @NotNull(message = "消费日期不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Date consumeDate;
+
+    /**
+     * 消费金额
+     */
+    @NotNull(message = "消费金额不能为空", groups = {AddGroup.class, EditGroup.class})
+    private BigDecimal consumeMoney;
+
+    /**
+     * 产生异常的请求数据
+     */
+    @NotBlank(message = "产生异常的请求数据不能为空", groups = {AddGroup.class, EditGroup.class})
+    private String requestData;
+
+    /**
+     * 异常说明
+     */
+    @NotBlank(message = "异常说明不能为空", groups = {AddGroup.class, EditGroup.class})
+    private String exceptInfo;
+
+    /**
+     * 处理标志(0-未处理 1-已处理)
+     */
+    @NotBlank(message = "处理标志不能为空", groups = {AddGroup.class, EditGroup.class})
+    private String status;
+
+    /**
+     * 处理说明
+     */
+    private String dealInfo;
+
+
+}

+ 9 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/controller/XfExceptionController.java

@@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.model.ErrorInfo;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -103,4 +104,12 @@ public class XfExceptionController extends BaseController {
                           @PathVariable Long[] exceptIds) {
         return toAjax(xfExceptionService.deleteWithValidByIds(List.of(exceptIds), true));
     }
+
+    @SaCheckPermission("consumption:xfException:edit")
+    @Log(title = "消费明细异常", businessType = BusinessType.UPDATE)
+    @PostMapping("/rePost/{exceptIds}")
+    public R<ErrorInfo> rePostXfException(@NotEmpty(message = "主键不能为空")
+                                              @PathVariable Long[] exceptIds){
+        return xfExceptionService.rePostXfException(List.of(exceptIds));
+    }
 }

+ 3 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/convert/RemoteBoConvert.java

@@ -4,6 +4,8 @@ import org.dromara.backstage.api.domain.bo.RemoteXfExceptionBo;
 import org.dromara.backstage.api.domain.vo.RemoteCardVo;
 import org.dromara.backstage.api.domain.vo.RemoteMealTypeVo;
 import org.dromara.backstage.api.domain.vo.RemoteUserAccountVo;
+import org.dromara.backstage.consumption.domain.XfConsumeDetail;
+import org.dromara.backstage.consumption.domain.XfException;
 import org.dromara.backstage.consumption.domain.bo.XfConsumeDetailOriginalBo;
 import org.dromara.backstage.consumption.domain.bo.XfExceptionBo;
 import org.dromara.backstage.consumption.domain.vo.XfConsumeDetailOriginalVo;
@@ -28,4 +30,5 @@ public interface RemoteBoConvert {
     RemoteBoConvert INSTANCE = Mappers.getMapper(RemoteBoConvert.class);
 
     void convertXfExceptionToBo(@MappingTarget XfExceptionBo target, RemoteXfExceptionBo source);
+    void convertXfExceptionToRemoteBo(@MappingTarget RemoteXfExceptionBo target, XfException source);
 }

+ 7 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/domain/vo/XfExceptionVo.java

@@ -2,6 +2,8 @@ package org.dromara.backstage.consumption.domain.vo;
 
 import java.math.BigDecimal;
 import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.dromara.backstage.consumption.domain.XfException;
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
@@ -31,6 +33,11 @@ public class XfExceptionVo implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
 
+    /**
+     * 消费明细异常Id,主键
+     */
+    private Long exceptId;
+
     /**
      * 物理卡号
      */

+ 6 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/IXfExceptionService.java

@@ -2,6 +2,8 @@ package org.dromara.backstage.consumption.service;
 
 import org.dromara.backstage.consumption.domain.vo.XfExceptionVo;
 import org.dromara.backstage.consumption.domain.bo.XfExceptionBo;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.domain.model.ErrorInfo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 
@@ -65,4 +67,8 @@ public interface IXfExceptionService {
      * @return 是否删除成功
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    R<ErrorInfo> rePostXfException(Collection<Long> ids);
+
+    Boolean updteRepostResult(XfExceptionBo bo);
 }

+ 59 - 22
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/consumption/service/impl/XfExceptionServiceImpl.java

@@ -1,24 +1,30 @@
 package org.dromara.backstage.consumption.service.impl;
 
-import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import cn.hutool.core.bean.BeanUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.backstage.consumption.domain.XfException;
 import org.dromara.backstage.consumption.domain.bo.XfExceptionBo;
 import org.dromara.backstage.consumption.domain.vo.XfExceptionVo;
-import org.dromara.backstage.consumption.domain.XfException;
 import org.dromara.backstage.consumption.mapper.XfExceptionMapper;
 import org.dromara.backstage.consumption.service.IXfExceptionService;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.domain.model.ErrorInfo;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.consume.api.RemoteConsumeService;
+import org.dromara.consume.api.domain.bo.RemoteXfExceptionDto;
+import org.springframework.stereotype.Service;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Collection;
+import java.util.*;
 
 /**
  * 消费明细异常Service业务层处理
@@ -29,9 +35,11 @@ import java.util.Collection;
 @RequiredArgsConstructor
 @Service
 public class XfExceptionServiceImpl implements IXfExceptionService {
-
     private final XfExceptionMapper baseMapper;
 
+    @DubboReference
+    private final RemoteConsumeService remoteConsumeService;
+
     /**
      * 查询消费明细异常
      *
@@ -39,7 +47,7 @@ public class XfExceptionServiceImpl implements IXfExceptionService {
      * @return 消费明细异常
      */
     @Override
-    public XfExceptionVo queryById(Long exceptId){
+    public XfExceptionVo queryById(Long exceptId) {
         return baseMapper.selectVoById(exceptId);
     }
 
@@ -80,17 +88,17 @@ public class XfExceptionServiceImpl implements IXfExceptionService {
         return lqw;
     }
 
-    private QueryWrapper<XfException> buildQueryWrapper(XfExceptionBo bo,String tableAlias) {
+    private QueryWrapper<XfException> buildQueryWrapper(XfExceptionBo bo, String tableAlias) {
         QueryWrapper<XfException> lqw = new QueryWrapper<>();
         String columnPrefix = "";
-        if(StringUtils.isNotBlank(tableAlias)){
+        if (StringUtils.isNotBlank(tableAlias)) {
             columnPrefix = tableAlias + ".";
         }
-        lqw.eq(bo.getFactoryId() != null, columnPrefix+"factory_id", bo.getFactoryId());
-        lqw.eq(bo.getTermNo() != null, columnPrefix+"term_no", bo.getTermNo());
-        lqw.like(StringUtils.isNotBlank(bo.getRealName()), columnPrefix+"real_name", bo.getRealName());
-        lqw.eq(bo.getConsumeDate() != null, columnPrefix+"consume_date", bo.getConsumeDate());
-        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), columnPrefix+"status", bo.getStatus());
+        lqw.eq(bo.getFactoryId() != null, columnPrefix + "factory_id", bo.getFactoryId());
+        lqw.eq(bo.getTermNo() != null, columnPrefix + "term_no", bo.getTermNo());
+        lqw.like(StringUtils.isNotBlank(bo.getRealName()), columnPrefix + "real_name", bo.getRealName());
+        lqw.eq(bo.getConsumeDate() != null, columnPrefix + "consume_date", bo.getConsumeDate());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), columnPrefix + "status", bo.getStatus());
         return lqw;
     }
 
@@ -127,7 +135,7 @@ public class XfExceptionServiceImpl implements IXfExceptionService {
     /**
      * 保存前的数据校验
      */
-    private void validEntityBeforeSave(XfException entity){
+    private void validEntityBeforeSave(XfException entity) {
         //TODO 做一些数据校验,如唯一约束
     }
 
@@ -140,9 +148,38 @@ public class XfExceptionServiceImpl implements IXfExceptionService {
      */
     @Override
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
-        if(isValid){
+        if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
         return baseMapper.deleteByIds(ids) > 0;
     }
+
+    @Override
+    public R<ErrorInfo> rePostXfException(Collection<Long> ids) {
+        //List<XfExceptionVo> list =
+        LambdaQueryWrapper<XfException> lqw = Wrappers.lambdaQuery();
+        lqw.in(XfException::getExceptId, ids);
+        List<XfException> list = baseMapper.selectList(lqw);
+        List<RemoteXfExceptionDto> records = new ArrayList<>();
+        for (XfException entity : list) {
+            records.add(BeanUtil.copyProperties(entity, RemoteXfExceptionDto.class));
+        }
+        List<RemoteXfExceptionDto> returns = remoteConsumeService.rePostConsumeData(records);
+        returns.forEach(p -> {
+            XfExceptionBo bo = BeanUtil.copyProperties(p, XfExceptionBo.class);
+            updteRepostResult(bo);
+        });
+        return R.ok();
+    }
+
+    @Override
+    public Boolean updteRepostResult(XfExceptionBo bo) {
+        LambdaUpdateWrapper<XfException> luw = new LambdaUpdateWrapper<>();
+        luw.set(XfException::getStatus, bo.getStatus());
+        luw.set(XfException::getDealInfo, bo.getDealInfo());
+        luw.set(XfException::getUpdateBy, LoginHelper.getUserId());
+        luw.set(XfException::getUpdateTime, new Date());
+        luw.eq(XfException::getExceptId, bo.getExceptId());
+        return baseMapper.update(null, luw) > 0;
+    }
 }

+ 2 - 2
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/ConsumeBusiness.java

@@ -311,7 +311,7 @@ public class ConsumeBusiness {
      * @return 对账结果对象 (ReconciliationResult)。
      * 包含处理后的结果信息,包括成功处理的记录、失败的记录以及异常详情。
      */
-    private ReconciliationResult processRecordsInParallel(List<ConsumptionBo> records) {
+    public ReconciliationResult processRecordsInParallel(List<ConsumptionBo> records) {
         ReconciliationResult result = new ReconciliationResult();
 
         // 循环处理
@@ -398,7 +398,7 @@ public class ConsumeBusiness {
      * 对账结果封装
      */
     @Data
-    private static class ReconciliationResult {
+    public static class ReconciliationResult {
         private final List<String> messages = Collections.synchronizedList(new ArrayList<>());
         private final AtomicInteger successCount = new AtomicInteger();
         private final AtomicInteger failCount = new AtomicInteger();

+ 32 - 5
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/dubbo/RemoteConsumeServiceImpl.java

@@ -11,9 +11,11 @@ import org.dromara.common.core.constant.DefaultConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.domain.model.ErrorInfo;
 import org.dromara.common.core.enums.SystemUseTypeEnum;
+import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.consume.api.RemoteConsumeService;
 import org.dromara.consume.api.domain.bo.RemoteConsumeBo;
 import org.dromara.consume.api.domain.bo.RemoteResultDto;
+import org.dromara.consume.api.domain.bo.RemoteXfExceptionDto;
 import org.dromara.server.common.domain.consume.bo.ConsumptionBo;
 import org.dromara.server.consume.business.ArcFaceBusiness;
 import org.dromara.server.consume.business.BaseBusiness;
@@ -23,6 +25,8 @@ import org.dromara.server.consume.service.IPtBagService;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * @ClassName RemoteConsumeServiceImpl
@@ -70,7 +74,7 @@ public class RemoteConsumeServiceImpl implements RemoteConsumeService {
     @Override
     public RemoteResultDto dealHikRequestConsume(RemoteConsumeBo remoteBo) {
         ConsumptionBo bo = RemoteConsumeBoConvert.INSTANCE.fromRemote(remoteBo);
-        R<ErrorInfo> result =  consumeBusiness.createHikOrder(bo, "", "");
+        R<ErrorInfo> result = consumeBusiness.createHikOrder(bo, "", "");
 
         RemoteConsumeBo updatedRemote = RemoteConsumeBoConvert.INSTANCE.toRemote(bo);
 
@@ -81,7 +85,7 @@ public class RemoteConsumeServiceImpl implements RemoteConsumeService {
     public RemoteResultDto dealHikUploadRecord(RemoteConsumeBo remoteBo) {
         ConsumptionBo bo = RemoteConsumeBoConvert.INSTANCE.fromRemote(remoteBo);
         bo.setUseType(SystemUseTypeEnum.CONSUME.code());
-        R<ErrorInfo> result =   consumeBusiness.postOrder(bo, "", "");
+        R<ErrorInfo> result = consumeBusiness.postOrder(bo, "", "");
         RemoteConsumeBo updatedRemote = RemoteConsumeBoConvert.INSTANCE.toRemote(bo);
 
         return new RemoteResultDto(result, updatedRemote);
@@ -91,7 +95,7 @@ public class RemoteConsumeServiceImpl implements RemoteConsumeService {
     public RemoteResultDto dealHikFullRecord(RemoteConsumeBo remoteBo) {
         ConsumptionBo bo = RemoteConsumeBoConvert.INSTANCE.fromRemote(remoteBo);
         bo.setUseType(SystemUseTypeEnum.CONSUME.code());
-        R<ErrorInfo> result =   consumeBusiness.fullOrder(bo, "", "");
+        R<ErrorInfo> result = consumeBusiness.fullOrder(bo, "", "");
         RemoteConsumeBo updatedRemote = RemoteConsumeBoConvert.INSTANCE.toRemote(bo);
 
         return new RemoteResultDto(result, updatedRemote);
@@ -100,8 +104,8 @@ public class RemoteConsumeServiceImpl implements RemoteConsumeService {
     @Override
     public RemoteResultDto dealHikUploadOffLineRecord(RemoteConsumeBo remoteBo) {
         ConsumptionBo bo = RemoteConsumeBoConvert.INSTANCE.fromRemote(remoteBo);
-        R<ErrorInfo> result =   consumeBusiness.fullOrder(bo, "", "");
-        if(R.isSuccess(result)){
+        R<ErrorInfo> result = consumeBusiness.fullOrder(bo, "", "");
+        if (R.isSuccess(result)) {
             if (ObjectUtil.equals(defaultConfig.getLocationFlag(), DefaultConstants.LOCAL_FLAG)) {
                 ThreadUtil.execAsync(() -> baseBusiness.sendCloudConsume(bo));
             }
@@ -132,4 +136,27 @@ public class RemoteConsumeServiceImpl implements RemoteConsumeService {
     public boolean cancleDeal(Long termNo, Integer termRecordId) {
         return baseBusiness.deleteOriginalRecord(termNo, termRecordId);
     }
+
+    @Override
+    public List<RemoteXfExceptionDto> rePostConsumeData(List<RemoteXfExceptionDto> remoteBos) {
+        List<RemoteXfExceptionDto> returns = new ArrayList<>();
+        remoteBos.forEach(p -> {
+            ConsumptionBo bo = JsonUtils.parseObject(p.getRequestData(), ConsumptionBo.class);
+            try {
+                R<ErrorInfo> response = consumeBusiness.postOrder(bo, "", "");
+
+                if (R.isSuccess(response)) {
+                    p.setStatus("1");
+                    p.setDealInfo("手动入账成功");
+                } else {
+                    p.setDealInfo("手动入账失败,需要人工核查数据");
+                }
+                returns.add(p);
+            } catch (Exception e) {
+                p.setDealInfo("手动入账失败,需要人工核查数据");
+                returns.add(p);
+            }
+        });
+        return returns;
+    }
 }