fix: require dedicated appointment cancellation command

This commit is contained in:
2026-10-11 14:14:51 +08:00
parent 43494cbfa3
commit 29b562ebf5
4 changed files with 32 additions and 4 deletions
@@ -112,6 +112,20 @@ class FbaAppointmentPersistenceTest {
assertEquals(2,db.queryForObject("SELECT COUNT(*) FROM ll_inbound_fba_appointment_item WHERE active=1",Integer.class));
}
}
@Test void restoringCancelledAppointmentRechecksClaimsAndPreservesCancellationHistory() {
try(var context=new AnnotationConfigApplicationContext(Config.class)) {
var service=context.getBean(InboundFbaAppointmentService.class);
var original=service.createFromSources("operator",request("restore-original"));
service.delete("operator",original.appointmentNo(),new CancelFbaAppointmentRequest(0,"仓库取消时段"));
var history=service.cancellationHistory(original.appointmentNo(),1,20).records();
var restored=service.update("operator",original.appointmentNo(),new UpdateFbaAppointmentRequest(request("unused").details(),1,"restore-command"));
assertEquals("PENDING",restored.appointmentStatus());
assertEquals(history,service.cancellationHistory(original.appointmentNo(),1,20).records());
assertEquals("CANCELLED",history.get(0).snapshot().appointmentStatus());
assertEquals("仓库取消时段",history.get(0).cancelReason());
assertThrows(ResponseStatusException.class,()->service.createFromSources("operator",request("overlap-restored")));
}
}
@Test void cancellationHistoryIsPersistedPagedScopedAndDoesNotExposeIdentities() throws Exception {
try(var context=new AnnotationConfigApplicationContext(Config.class)) {
var service=context.getBean(InboundFbaAppointmentService.class);
@@ -154,6 +154,19 @@ class InboundFbaAppointmentServiceTest {
assertThrows(ResponseStatusException.class,()->service.update("operator",result.appointmentNo(),new UpdateFbaAppointmentRequest(pending("change"),0,"blocked-update")));
assertThrows(ResponseStatusException.class,()->service.delete("operator",result.appointmentNo(),new CancelFbaAppointmentRequest(0,"收货方取消时段")));assertTrue(storedItems.stream().allMatch(InboundFbaAppointmentItem::getActive));
}
@Test void ordinaryUpdateCannotCancelOrUseTheExistingRemarkAsCancellationReason() {
var original=service.createFromSources("operator",request("cancel-bypass",pending("原业务备注"),"ORDER:1"));
var details=new FbaAppointmentDetails(null,null,null,null,null,null,"CANCELLED","原业务备注",null,null);
clearInvocations(commands,headers,items);
var error=assertThrows(ResponseStatusException.class,()->service.update("operator",original.appointmentNo(),new UpdateFbaAppointmentRequest(details,0,"bypass")));
assertEquals(400,error.getStatusCode().value());
assertEquals("PENDING",storedHeaders.get(0).getAppointmentStatus());
assertEquals("原业务备注",storedHeaders.get(0).getAppointmentRemark());
assertEquals(0,storedHeaders.get(0).getVersion());
assertTrue(storedItems.stream().allMatch(InboundFbaAppointmentItem::getActive));
verify(commands,never()).begin(anyString(),anyString(),anyString(),anyString(),any());
verify(headers,never()).update(any(InboundFbaAppointment.class),any());
}
@Test void cancellationPreservesConfirmedFactsAndHistoryButCannotRestoreOverAnotherActiveClaim() {
var result=service.createFromSources("operator",request("confirmed",confirmed(),"ORDER:1"));
service.delete("operator",result.appointmentNo(),new CancelFbaAppointmentRequest(0,"收货方取消时段"));