test(finance): cover overseas fee replay and frozen lifecycle
This commit is contained in:
@@ -164,4 +164,77 @@ class BusinessFeeSourceEventServiceTest {
|
||||
null, base.traceId(), "LASTLEG:FEE:701:" + version, null, payload,
|
||||
EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(payload)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sameEventIdWithDifferentPayloadIsRejectedWithoutWrites() {
|
||||
var event = payableEvent("PUBLISHED", 1);
|
||||
when(jdbc.queryForList(startsWith("SELECT payload_hash,status"), eq("LASTLEG"), eq(event.eventId())))
|
||||
.thenReturn(List.of(Map.of("payload_hash", "different", "status", "PROCESSED", "result_resource_id", 901L)));
|
||||
assertThatThrownBy(() -> service.consume(event)).hasMessageContaining("同一事件ID");
|
||||
verify(jdbc, never()).update(anyString(), any(Object[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sameSourceVersionWithDifferentHashCannotOverwriteCost() {
|
||||
var event = payableEvent("PUBLISHED", 1);
|
||||
existingVersion("different", "AVAILABLE");
|
||||
assertThatThrownBy(() -> service.consume(event)).hasMessageContaining("同一来源版本");
|
||||
noFinancialWrites();
|
||||
}
|
||||
|
||||
@Test
|
||||
void voidedSourceCannotBeRevivedByPublicationReplay() {
|
||||
var event = payableEvent("PUBLISHED", 1);
|
||||
existingVersion(event.payload().get("sourceHash").asText(), "VOIDED");
|
||||
assertThat(service.consume(event)).isEqualTo(901L);
|
||||
noFinancialWrites();
|
||||
}
|
||||
|
||||
@Test
|
||||
void voidTargetsOnlyMatchingOverseasCostVersion() {
|
||||
var event = payableEvent("VOIDED", 1);
|
||||
existingVersion(event.payload().get("sourceHash").asText(), "AVAILABLE");
|
||||
assertThat(service.consume(event)).isEqualTo(901L);
|
||||
verify(jdbc).update(startsWith("UPDATE fin_cost SET status='VOIDED'"),
|
||||
eq("LASTLEG"), eq("OVERSEAS_CONTAINER_FEE"), eq(701L), eq(1));
|
||||
verify(jdbc, never()).update(startsWith("INSERT INTO fin_cost"), any(Object[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void frozenSourceRejectsAdjustmentWithoutReplacingSourceOrCost() {
|
||||
var event = payableEvent("ADJUSTED", 2);
|
||||
when(jdbc.queryForObject(startsWith("SELECT COUNT(*) FROM fin_fee_source f WHERE f.source_system=?"),
|
||||
eq(Integer.class), eq("LASTLEG"), eq("OVERSEAS_CONTAINER_FEE"), eq(701L))).thenReturn(1);
|
||||
assertThatThrownBy(() -> service.consume(event)).hasMessageContaining("禁止调整或替代");
|
||||
noFinancialWrites();
|
||||
}
|
||||
|
||||
@Test
|
||||
void frozenSourceRejectsVoidWithoutChangingSourceOrCost() {
|
||||
var event = payableEvent("VOIDED", 1);
|
||||
existingVersion(event.payload().get("sourceHash").asText(), "AVAILABLE");
|
||||
when(jdbc.queryForObject(startsWith("SELECT COUNT(*) FROM fin_fee_source f WHERE f.id=?"),
|
||||
eq(Integer.class), eq(901L))).thenReturn(1);
|
||||
assertThatThrownBy(() -> service.consume(event)).hasMessageContaining("禁止作废");
|
||||
noFinancialWrites();
|
||||
}
|
||||
|
||||
private EventEnvelope payableEvent(String action, int version) {
|
||||
when(suppliers.requireActive(71L, null)).thenReturn(
|
||||
new com.baiyue.finance.client.WarehouseSupplierClient.SupplierSnapshot(71L, "供应商", null, "ACTIVE"));
|
||||
return containerEvent("CNY", "61", action, version);
|
||||
}
|
||||
|
||||
private void existingVersion(String hash, String status) {
|
||||
when(jdbc.queryForList(startsWith("SELECT id,source_hash,status FROM fin_fee_source"),
|
||||
eq("LASTLEG"), eq("OVERSEAS_CONTAINER_FEE"), eq(701L), eq(1)))
|
||||
.thenReturn(List.of(Map.of("id", 901L, "source_hash", hash, "status", status)));
|
||||
}
|
||||
|
||||
private void noFinancialWrites() {
|
||||
verify(jdbc, never()).update(startsWith("INSERT INTO fin_fee_source"), any(Object[].class));
|
||||
verify(jdbc, never()).update(startsWith("UPDATE fin_fee_source"), any(Object[].class));
|
||||
verify(jdbc, never()).update(startsWith("INSERT INTO fin_cost"), any(Object[].class));
|
||||
verify(jdbc, never()).update(startsWith("UPDATE fin_cost"), any(Object[].class));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user