提交
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
package com.baiyue.lastleg.palletops.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.palletops.service.PalletOperationRecoveryService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
/** 受库存管理权限保护的人工恢复入口,不允许PDA自行批准技术状态关闭。 */
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/last-leg/pallet-operation-recoveries")
|
||||
@PreAuthorize("hasAuthority('lastleg:inventory:manage')")
|
||||
public class PlatformPalletOperationRecoveryController {
|
||||
private final PalletOperationRecoveryService service;
|
||||
/** 注入恢复业务服务。 */
|
||||
public PlatformPalletOperationRecoveryController(PalletOperationRecoveryService service){this.service=service;}
|
||||
/** 管理员读取原作业证据。 */
|
||||
@GetMapping("/{id}") public ApiResponse<PalletOperationRecoveryService.State> inspect(@PathVariable long id){return ApiResponse.success(service.inspect(id));}
|
||||
/** 以认证管理员身份审计关闭。 */
|
||||
@PostMapping("/{id}/close-no-effect")
|
||||
public ApiResponse<PalletOperationRecoveryService.Recovery> close(@PathVariable long id,@AuthenticationPrincipal AuthenticatedUser user,@Valid @RequestBody PalletOperationRecoveryService.Close request){return ApiResponse.success(service.close(id,String.valueOf(user.userId()),request));}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baiyue.lastleg.palletops.mapper;
|
||||
|
||||
import com.baiyue.lastleg.palletops.entity.PdaPalletOperation;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 恢复与远端意图使用同一行CAS,恢复关闭后旧执行线程不能继续发起远端写入。 */
|
||||
@Mapper
|
||||
public interface PalletOperationRecoveryMapper {
|
||||
/** 读取原作业技术状态。 */
|
||||
@Select("SELECT * FROM ll_pda_pallet_operation WHERE id=#{id}")
|
||||
PdaPalletOperation find(@Param("id") long id);
|
||||
/** 恢复审批与远端意图按原行串行。 */
|
||||
@Select("SELECT * FROM ll_pda_pallet_operation WHERE id=#{id} FOR UPDATE")
|
||||
PdaPalletOperation lock(@Param("id") long id);
|
||||
/** 恢复关闭后拒绝继续持久化远端意图。 */
|
||||
@Update("UPDATE ll_pda_pallet_operation SET remote_transitions_json=#{json},updated_at=#{at} WHERE id=#{id} AND status='PROCESSING'")
|
||||
int journal(@Param("id") long id,@Param("json") String json,@Param("at") LocalDateTime at);
|
||||
/** 条件关闭原作业并保存恢复审计。 */
|
||||
@Update("UPDATE ll_pda_pallet_operation SET status='RECOVERED_NO_EFFECT',result_json=#{audit},updated_at=#{at} WHERE id=#{id} AND status IN ('PROCESSING','FAILED_COMPENSATED')")
|
||||
int close(@Param("id") long id,@Param("audit") String audit,@Param("at") LocalDateTime at);
|
||||
/** 旧执行线程不能用失败结果覆盖已恢复或已完成终态。 */
|
||||
@Update("UPDATE ll_pda_pallet_operation SET status=#{status},last_error=#{error},updated_at=#{at} WHERE id=#{id} AND status NOT IN ('RECOVERED_NO_EFFECT','COMPLETED')")
|
||||
int fail(@Param("id") long id,@Param("status") String status,@Param("error") String error,@Param("at") LocalDateTime at);
|
||||
}
|
||||
+7
-3
@@ -53,11 +53,15 @@ public interface PdaPalletOperationMapper extends BaseMapper<PdaPalletOperation>
|
||||
@Options(useCache=false, flushCache=Options.FlushCachePolicy.TRUE)
|
||||
List<MutationPallet> mutationPallets(@Param("warehouseId") String warehouseId, @Param("applicationNos") List<String> applicationNos);
|
||||
|
||||
/** 收齐原入仓、退回实收、计划及原生退货业务订单,不使用MIN或其他客户代表行。 */
|
||||
/** 收齐真实尾程订单;入仓快照ID经同客户来源分片解析,缺失关联保留空值以拒绝改绑。 */
|
||||
@Select("<script>SELECT a.customer_id AS customerId,a.lastleg_order_id AS orderId FROM ll_relabel_application a WHERE a.relabel_no IN " + MUTATION_APPS
|
||||
+ " UNION SELECT i.customer_id,i.source_inbound_order_id FROM ll_relabel_item i JOIN ll_relabel_application a ON a.id=i.application_id AND a.customer_id=i.customer_id "
|
||||
+ " UNION SELECT i.customer_id,original.id FROM ll_relabel_item i JOIN ll_relabel_application a ON a.id=i.application_id AND a.customer_id=i.customer_id "
|
||||
+ "LEFT JOIN ll_inbound_order inbound ON inbound.id=i.source_inbound_order_id AND inbound.customer_id=i.customer_id "
|
||||
+ "LEFT JOIN ll_order original ON original.customer_id=inbound.customer_id AND original.source_inbound_id=inbound.source_inbound_id "
|
||||
+ "WHERE a.relabel_no IN " + MUTATION_APPS + " AND i.return_carton_id IS NULL"
|
||||
+ " UNION SELECT p.customer_id,b.inbound_order_id FROM ll_inventory_position p JOIN ll_inventory_balance b ON b.id=p.balance_id AND b.customer_id=p.customer_id "
|
||||
+ " UNION SELECT p.customer_id,original.id FROM ll_inventory_position p JOIN ll_inventory_balance b ON b.id=p.balance_id AND b.customer_id=p.customer_id "
|
||||
+ "LEFT JOIN ll_inbound_order inbound ON inbound.id=b.inbound_order_id AND inbound.customer_id=b.customer_id "
|
||||
+ "LEFT JOIN ll_order original ON original.customer_id=inbound.customer_id AND original.source_inbound_id=inbound.source_inbound_id "
|
||||
+ "WHERE p.overseas_warehouse_id=#{warehouseId} AND p.pallet_id IN " + MUTATION_IDS
|
||||
+ " UNION SELECT r.customer_id,r.order_id FROM ll_inbound_stock_receipt r JOIN ll_inventory_position p ON p.id=r.inventory_position_id AND p.customer_id=r.customer_id "
|
||||
+ "WHERE p.overseas_warehouse_id=#{warehouseId} AND r.warehouse_pallet_id IN " + MUTATION_IDS
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.baiyue.lastleg.palletops.repository;
|
||||
|
||||
import com.baiyue.lastleg.palletops.mapper.PalletOperationRecoveryMapper;
|
||||
import com.baiyue.lastleg.palletops.entity.PdaPalletOperation;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 只封装本域作业记录的读取、串行锁和条件写入。 */
|
||||
@Repository
|
||||
public class PalletOperationRecoveryRepository {
|
||||
private final PalletOperationRecoveryMapper mapper;
|
||||
/** 注入本域作业条件写入映射。 */
|
||||
public PalletOperationRecoveryRepository(PalletOperationRecoveryMapper mapper){this.mapper=mapper;}
|
||||
/** 读取原作业。 */
|
||||
public PdaPalletOperation find(long id){return mapper.find(id);}
|
||||
/** 为恢复审批锁定原记录。 */
|
||||
public PdaPalletOperation lock(long id){return mapper.lock(id);}
|
||||
/** 条件持久化远端意图。 */
|
||||
public boolean journal(long id,String json,LocalDateTime at){return mapper.journal(id,json,at)==1;}
|
||||
/** 条件保存恢复终态和审计。 */
|
||||
public boolean close(long id,String audit,LocalDateTime at){return mapper.close(id,audit,at)==1;}
|
||||
/** 失败写入同样保护已恢复终态。 */
|
||||
public boolean fail(long id,String status,String error,LocalDateTime at){return mapper.fail(id,status,error,at)==1;}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.baiyue.lastleg.palletops.service;
|
||||
|
||||
import com.baiyue.lastleg.palletops.repository.PalletOperationRecoveryRepository;
|
||||
import com.baiyue.lastleg.palletops.entity.PdaPalletOperation;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 只关闭已超时且从未发出远端请求的换标组托,不把未知远端结果推定为无效果。 */
|
||||
@Service
|
||||
public class PalletOperationRecoveryService {
|
||||
private final PalletOperationRecoveryRepository repository;
|
||||
private final ObjectMapper json;
|
||||
/** 注入本域作业仓储和统一序列化器。 */
|
||||
public PalletOperationRecoveryService(PalletOperationRecoveryRepository repository,ObjectMapper json){this.repository=repository;this.json=json;}
|
||||
public record Close(@Positive long warehouseId,@NotNull LocalDateTime expectedUpdatedAt,
|
||||
@NotBlank @Size(max=255) String idempotencyKey,@NotBlank @Size(max=1000) String reason){}
|
||||
public record Recovery(String operationId,String status,String recoveryKey,String operatorId,String reason,
|
||||
String previousStatus,String previousError,LocalDateTime closedAt,boolean replayed){}
|
||||
public record State(String operationId,String status,String operatorKey,long warehouseId,String operationType,
|
||||
String requestHash,String remoteTransitionsJson,String lastError,LocalDateTime updatedAt){}
|
||||
/** 管理员只读核对原记录和不可变请求哈希,不返回其他账号会话。 */
|
||||
@Transactional(readOnly=true)
|
||||
public State inspect(long id){var row=required(repository.find(id));return new State(String.valueOf(id),row.getStatus(),row.getOperatorKey(),row.getOverseasWarehouseId(),row.getOperationType(),row.getRequestHash(),row.getRemoteTransitionsJson(),row.getLastError(),row.getUpdatedAt());}
|
||||
/** 行锁与远端意图CAS互斥;审计写在原作业结果中,原错误和请求哈希保留。 */
|
||||
@Transactional
|
||||
public Recovery close(long id,String operatorId,Close request){
|
||||
var row=required(repository.lock(id));
|
||||
if(row.getOverseasWarehouseId()!=request.warehouseId())throw conflict("作业不属于指定仓库");
|
||||
if("RECOVERED_NO_EFFECT".equals(row.getStatus())){
|
||||
var existing=read(row.getResultJson());
|
||||
if(!existing.recoveryKey().equals(request.idempotencyKey())||!existing.reason().equals(request.reason())||!existing.operatorId().equals(operatorId))throw conflict("恢复幂等键或载荷不一致");
|
||||
return new Recovery(existing.operationId(),existing.status(),existing.recoveryKey(),existing.operatorId(),existing.reason(),existing.previousStatus(),existing.previousError(),existing.closedAt(),true);
|
||||
}
|
||||
// 已补偿失败仍须核对没有任何远端意图,不能仅凭补偿状态推断无效果。
|
||||
if(!"RELABEL_PALLET_DISASSEMBLE".equals(row.getOperationType())||!("PROCESSING".equals(row.getStatus())||"FAILED_COMPENSATED".equals(row.getStatus())))throw conflict("只允许恢复超时的处理中或已补偿失败换标组托");
|
||||
if(!request.expectedUpdatedAt().equals(row.getUpdatedAt())||row.getUpdatedAt()==null||row.getUpdatedAt().isAfter(LocalDateTime.now().minusMinutes(15)))throw conflict("作业仍活跃或版本已变化,请刷新后核对");
|
||||
if(row.getResultJson()!=null&&!row.getResultJson().isBlank())throw conflict("作业已有结果,不能关闭为无效果");
|
||||
try{if(row.getRemoteTransitionsJson()!=null&&!row.getRemoteTransitionsJson().isBlank()){
|
||||
var attempts=json.readTree(row.getRemoteTransitionsJson());
|
||||
if(!attempts.isArray()||!attempts.isEmpty())throw conflict("存在远端意图或回执,必须先核实远端效果,不能执行无效果恢复");
|
||||
}}catch(com.fasterxml.jackson.core.JsonProcessingException e){throw conflict("远端意图记录不可解析,禁止恢复");}
|
||||
var result=new Recovery(String.valueOf(id),"RECOVERED_NO_EFFECT",request.idempotencyKey(),operatorId,request.reason(),row.getStatus(),row.getLastError(),LocalDateTime.now(),false);
|
||||
try{if(!repository.close(id,json.writeValueAsString(result),result.closedAt()))throw conflict("作业状态已变化,恢复未写入");}
|
||||
catch(com.fasterxml.jackson.core.JsonProcessingException e){throw new IllegalStateException("恢复审计序列化失败",e);}
|
||||
return result;
|
||||
}
|
||||
/** 重放只读取已持久化的恢复审计。 */
|
||||
private Recovery read(String value){try{return json.readValue(value,Recovery.class);}catch(Exception e){throw conflict("恢复审计不可读取");}}
|
||||
/** 原记录不存在时明确拒绝,不新建作业。 */
|
||||
private PdaPalletOperation required(PdaPalletOperation row){if(row==null)throw new ResponseStatusException(HttpStatus.NOT_FOUND,"托盘作业不存在");return row;}
|
||||
/** 统一表达恢复条件或幂等载荷冲突。 */
|
||||
private ResponseStatusException conflict(String message){return new ResponseStatusException(HttpStatus.CONFLICT,message);}
|
||||
}
|
||||
+35
-9
@@ -54,6 +54,7 @@ import java.util.HexFormat;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -63,6 +64,7 @@ import java.util.stream.Collectors;
|
||||
public class PdaPalletOperationService {
|
||||
@Resource private PdaPalletOperationMapper mapper;
|
||||
@Resource private PdaPalletOperationRepository mutationRepository;
|
||||
@Resource private com.baiyue.lastleg.palletops.repository.PalletOperationRecoveryRepository recoveryRepository;
|
||||
@Resource private PhysicalPalletSerialPort physicalPalletSerial;
|
||||
private Clock mutationClock = Clock.systemUTC();
|
||||
@Resource private com.baiyue.lastleg.inventory.command.mapper.InventoryCommandMapper inventoryCommands;
|
||||
@@ -257,7 +259,10 @@ public class PdaPalletOperationService {
|
||||
List<RelabelItem> selected = relabelItems.selectList(new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<RelabelItem>()
|
||||
.eq("application_id", application.getId()).eq("customer_id", application.getCustomerId())
|
||||
.in("carton_mark", marks));
|
||||
if (selected.size() != marks.size()
|
||||
// 同一退货实物来源允许多个SKU按件任务;普通箱任务仍必须一箱一项。
|
||||
boolean bulkSkuSource = selected.stream().allMatch(item -> item.getReturnCartonId() != null
|
||||
&& "RETURN_BULK_SKU_LABEL".equals(item.getOperationType()));
|
||||
if ((!bulkSkuSource && selected.size() != marks.size())
|
||||
|| selected.stream().map(RelabelItem::getCartonMark).distinct().count() != marks.size()) {
|
||||
throw conflict("提交的箱唛不属于当前换标单");
|
||||
}
|
||||
@@ -417,8 +422,10 @@ public class PdaPalletOperationService {
|
||||
// 先取得共同串行锁再触碰远端;本地失败补偿也必须在该锁释放前结束。
|
||||
try {
|
||||
applyPhysical(operation,identity.overseasWarehouseId(),target,"OCCUPIED",target.locationId(),key,"退货换标组托",journal);
|
||||
Set<Long> movedCartons = new HashSet<>();
|
||||
for (int index = 0; index < cartons.size(); index++) {
|
||||
RelabelItem item = selected.get(index);
|
||||
if (!movedCartons.add(item.getReturnCartonId())) continue;
|
||||
ReturnInventoryCarton carton = returnCartons.lockId(item.getReturnCartonId());
|
||||
if (carton == null || !Objects.equals(carton.getCustomerId(), application.getCustomerId())
|
||||
|| (unboundSource ? (org.springframework.util.StringUtils.hasText(carton.getPalletCode()) && !"UNBOUND".equalsIgnoreCase(carton.getPalletCode()))
|
||||
@@ -426,8 +433,18 @@ public class PdaPalletOperationService {
|
||||
|| !Objects.equals(carton.getRelabelApplicationId(), application.getId())
|
||||
|| !"RELABEL_PENDING".equals(carton.getStatus()))
|
||||
throw conflict("退货换标来源库存已变化,请刷新后重试");
|
||||
var sameSource = selected.stream().filter(line -> Objects.equals(line.getReturnCartonId(), carton.getId())).toList();
|
||||
long move = "RETURN_BULK_SKU_LABEL".equals(item.getOperationType())
|
||||
? value(item.getNotifiedPackageCount()) : value(carton.getTotalQuantity());
|
||||
? sameSource.stream().mapToLong(line -> value(line.getNotifiedPackageCount())).sum() : value(carton.getTotalQuantity());
|
||||
if (sameSource.size() > 1) {
|
||||
// 同一实物的多SKU整批只移动一次;部分混源必须先拆成独立实物,不能逐SKU虚构新箱。
|
||||
var requestedSkus = new HashMap<String, Long>();
|
||||
sameSource.forEach(line -> requestedSkus.merge(line.getSkuCode().toUpperCase(Locale.ROOT), (long) value(line.getNotifiedPackageCount()), Long::sum));
|
||||
var actualSkus = new HashMap<String, Long>();
|
||||
returnCartonItems.lockCarton(carton.getId()).forEach(line -> actualSkus.merge(line.getSkuCode().toUpperCase(Locale.ROOT), value(line.getQuantity()), Long::sum));
|
||||
if (move != value(carton.getTotalQuantity()) || !requestedSkus.equals(actualSkus))
|
||||
throw conflict("多SKU来源须整批完成并核平;部分贴标请先分拣为独立实物");
|
||||
}
|
||||
if (move <= 0 || move > value(carton.getTotalQuantity())) throw conflict("来源托盘可拆数量不足");
|
||||
if (move < value(carton.getTotalQuantity())) {
|
||||
splitReturnRelabelCarton(application, item, carton, target, move);
|
||||
@@ -439,7 +456,7 @@ public class PdaPalletOperationService {
|
||||
returnCartons.updateById(carton);
|
||||
}
|
||||
}
|
||||
recordReturnRelabelBinding(identity, application, selected, target.palletCode());
|
||||
recordReturnRelabelBinding(identity, application, selected, source == null ? "" : source.palletCode(), target.palletCode());
|
||||
List<PalletOperationResponses.PalletContent> contents = source == null
|
||||
? List.of(content(identity.overseasWarehouseId(), physical.resolve(target.palletCode())))
|
||||
: List.of(content(identity.overseasWarehouseId(), physical.resolve(source.palletCode())),
|
||||
@@ -972,6 +989,7 @@ public class PdaPalletOperationService {
|
||||
return marks;
|
||||
}
|
||||
|
||||
/** 记录经过实物来源校验的逐任务绑定,避免多来源数组失去箱与托盘的精确关系。 */
|
||||
private void recordRelabelBinding(PdaWarehouseIdentity identity, RelabelMutation mutation,
|
||||
Map<Long, InventoryPosition> targets) {
|
||||
var app = mutation.application();
|
||||
@@ -987,7 +1005,11 @@ public class PdaPalletOperationService {
|
||||
mutation.itemsByPosition().values().stream().flatMap(List::stream).toList(),
|
||||
mutation.itemsByPosition().keySet().stream().map(positions::selectById).filter(Objects::nonNull).findFirst().orElseThrow().getPalletId(),
|
||||
targets.values().iterator().next().getPalletId(), targets.values().iterator().next().getPalletNo(), mutation.measuredCartons());
|
||||
record.setDetailJson(write(Map.of("round", Objects.toString(task.getReviewedAt(), "INITIAL"),
|
||||
var itemBindings = mutation.itemsByPosition().entrySet().stream().flatMap(entry -> entry.getValue().stream().map(item ->
|
||||
Map.of("itemId", String.valueOf(item.getId()), "sourceKnown", true,
|
||||
"sourcePalletCode", Objects.toString(positions.selectById(entry.getKey()).getPalletNo(), ""),
|
||||
"targetPalletCode", targets.get(entry.getKey()).getPalletNo()))).toList();
|
||||
record.setDetailJson(write(Map.of("round", Objects.toString(task.getReviewedAt(), "INITIAL"), "itemBindings", itemBindings,
|
||||
"measuredCartons", measured,
|
||||
"cartonMarks", mutation.itemsByPosition().values().stream().flatMap(List::stream).map(RelabelItem::getCartonMark).toList(),
|
||||
"targetPallets", targets.values().stream().map(InventoryPosition::getPalletNo).distinct().toList(),
|
||||
@@ -996,8 +1018,9 @@ public class PdaPalletOperationService {
|
||||
relabelWorkHistory.insert(record);
|
||||
}
|
||||
|
||||
/** 来源实托在变更前已经核对,历史只记录该次校验值,不反查变更后的库存托盘。 */
|
||||
private void recordReturnRelabelBinding(PdaWarehouseIdentity identity, RelabelApplication app,
|
||||
List<RelabelItem> items, String targetPallet) {
|
||||
List<RelabelItem> items, String sourcePallet, String targetPallet) {
|
||||
var task = relabelWorkTasks.find(app.getCustomerId(), app.getId());
|
||||
if (task == null) throw conflict("退货换标作业任务不存在,不能记录组托");
|
||||
var record = new com.baiyue.lastleg.relabel.pda.entity.PdaRelabelHistory();
|
||||
@@ -1007,6 +1030,8 @@ public class PdaPalletOperationService {
|
||||
record.setOperatorKey(identity.operatorKey()); record.setOperatorName(identity.operatorName());
|
||||
record.setCreatedAt(LocalDateTime.now());
|
||||
record.setDetailJson(write(Map.of("round", Objects.toString(task.getReviewedAt(), "INITIAL"),
|
||||
"itemBindings", items.stream().map(item -> Map.of("itemId", String.valueOf(item.getId()), "sourceKnown", true,
|
||||
"sourcePalletCode", sourcePallet, "targetPalletCode", targetPallet)).toList(),
|
||||
"cartonMarks", items.stream().map(RelabelItem::getCartonMark).toList(),
|
||||
"targetPallets", List.of(targetPallet))));
|
||||
relabelWorkHistory.insert(record);
|
||||
@@ -1200,17 +1225,18 @@ public class PdaPalletOperationService {
|
||||
newTransaction.executeWithoutResult(status -> {
|
||||
PdaPalletOperation operation = mapper.selectById(operationId);
|
||||
if (operation == null) throw new IllegalStateException("实托作业意图记录不存在,不能发出远端请求");
|
||||
operation.setRemoteTransitionsJson(write(attempts)); operation.setUpdatedAt(LocalDateTime.now());
|
||||
mapper.updateById(operation);
|
||||
if (!recoveryRepository.journal(operationId, write(attempts), LocalDateTime.now()))
|
||||
throw conflict("作业已由管理员恢复关闭,禁止继续发出远端请求");
|
||||
});
|
||||
}
|
||||
/** 条件记录失败,避免旧线程覆盖管理员已恢复的原记录。 */
|
||||
private void fail(long operationId, RuntimeException failure, boolean compensated) {
|
||||
newTransaction.executeWithoutResult(status -> {
|
||||
PdaPalletOperation operation = mapper.selectById(operationId);
|
||||
if (operation == null || "COMPLETED".equals(operation.getStatus())) return;
|
||||
if (operation == null || "COMPLETED".equals(operation.getStatus()) || "RECOVERED_NO_EFFECT".equals(operation.getStatus())) return;
|
||||
operation.setStatus(compensated ? "FAILED_COMPENSATED" : "COMPENSATION_REQUIRED");
|
||||
operation.setLastError(limit(failure.getMessage(), 2000)); operation.setUpdatedAt(LocalDateTime.now());
|
||||
mapper.updateById(operation);
|
||||
recoveryRepository.fail(operationId, operation.getStatus(), operation.getLastError(), operation.getUpdatedAt());
|
||||
});
|
||||
}
|
||||
private boolean compensate(long warehouseId, List<PalletPhysicalGateway.Transition> transitions) {
|
||||
|
||||
Reference in New Issue
Block a user