fix(finance): include billed sources in trip financial attribution

This commit is contained in:
2026-10-05 12:35:38 +08:00
parent f13d340620
commit adaac7aca4
3 changed files with 33 additions and 4 deletions
@@ -24,6 +24,8 @@ class TripFinanceQueryServiceTest {
void bill(long source,int version) {
jdbc.update("INSERT INTO fin_bill VALUES(1,1,'BILL-A','CNY','ISSUED')");
jdbc.update("INSERT INTO fin_bill_line VALUES(1,1,?,?,'CNY')",source,version);
// Fixture models the real ISSUE source state; this does not call the write service.
jdbc.update("UPDATE fin_fee_source SET status='BILLED' WHERE id=? AND status='AVAILABLE'",source);
}
void receipt(String amount) {
jdbc.update("INSERT INTO fin_receipt VALUES(1,1,'CONFIRMED','CNY')");
@@ -35,6 +37,33 @@ class TripFinanceQueryServiceTest {
assertThat(result.totals().get(0).receivableAmount()).isEqualByComparingTo("20");
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("ATTRIBUTED");
}
@Test void legalSourceAndBillStatesKeepReceivableAndRecordedReceiptAcrossLifecycle() {
for(String sourceStatus:List.of("AVAILABLE","BILLED","SETTLED"))for(String billStatus:List.of("ISSUED","PARTIALLY_PAID","PAID")) {
setup();fee(1,1,"DL-A",1,"CNY","20",sourceStatus);bill(1,1);
jdbc.update("UPDATE fin_fee_source SET status=?",sourceStatus);
jdbc.update("UPDATE fin_bill SET status=?",billStatus);
if(!"ISSUED".equals(billStatus))receipt("PAID".equals(billStatus)?"20":"3.5");
var result=service.query(request(true));
assertThat(result.sources()).as(sourceStatus+"/"+billStatus).hasSize(1);
assertThat(result.sources().get(0).status()).isEqualTo(sourceStatus);
assertThat(result.totals().get(0).receivableAmount()).isEqualByComparingTo("20");
assertThat(result.documents()).hasSize(1);
if("ISSUED".equals(billStatus)) {
assertThat(result.totals().get(0).receivedAmount()).isNull();
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("PENDING_ALLOCATION");
} else {
assertThat(result.totals().get(0).receivedAmount()).isEqualByComparingTo("PAID".equals(billStatus)?"20":"3.5");
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("ATTRIBUTED");
}
}
}
@Test void lockedVoidedAndSupersededSourcesRemainExcluded() {
for(String status:List.of("LOCKED","VOIDED","SUPERSEDED")) {
setup();fee(1,1,"DL-A",1,"CNY","20",status);bill(1,1);receipt("20");
var result=service.query(request(true));assertThat(result.sources()).as(status).isEmpty();
assertThat(result.totals()).isEmpty();assertThat(result.documents()).isEmpty();
}
}
@Test void issuedPartialAndPaidBillsKeepTheirConfirmedAllocation() {
for(String status:List.of("ISSUED","PARTIALLY_PAID","PAID")) {
setup();fee(1,1,"DL-A",1,"CNY","20","AVAILABLE");bill(1,1);
@@ -78,8 +107,8 @@ class TripFinanceQueryServiceTest {
assertThat(service.query(request(true)).totals().get(0).receivableAmount()).isEqualByComparingTo("0");
}
@Test void latestVoidedDoesNotFallBackAndOtherCustomerExcluded() {
fee(1,1,"DL-A",1,"CNY","20","AVAILABLE");fee(2,1,"DL-A",2,"CNY","20","VOIDED");
fee(3,2,"DL-A",1,"CNY","999","AVAILABLE");
fee(1,1,"DL-A",1,"CNY","20","BILLED");fee(2,1,"DL-A",2,"CNY","20","VOIDED");
fee(3,2,"DL-A",1,"CNY","999","BILLED");
var result=service.query(request(true));assertThat(result.sources()).isEmpty();assertThat(result.status()).isEqualTo("PENDING_ALLOCATION");
}
@Test void currenciesSeparateAndNoReceiptPermissionMasksDocuments() {