fix(finance): retain trip receipts after partial and full payment
This commit is contained in:
@@ -49,7 +49,7 @@ public class TripFinanceQueryService {
|
|||||||
SELECT b.id,b.tenant_id,b.bill_no,b.currency_code,l.source_id FROM fin_bill_line l
|
SELECT b.id,b.tenant_id,b.bill_no,b.currency_code,l.source_id FROM fin_bill_line l
|
||||||
JOIN fin_bill b ON b.id=l.bill_id AND b.tenant_id=l.tenant_id
|
JOIN fin_bill b ON b.id=l.bill_id AND b.tenant_id=l.tenant_id
|
||||||
JOIN fin_fee_source f ON f.id=l.source_id AND f.customer_id=l.tenant_id AND f.source_fee_version=l.source_version
|
JOIN fin_fee_source f ON f.id=l.source_id AND f.customer_id=l.tenant_id AND f.source_fee_version=l.source_version
|
||||||
WHERE l.source_id IN (:ids) AND b.status='ISSUED'
|
WHERE l.source_id IN (:ids) AND b.status IN ('ISSUED','PARTIALLY_PAID','PAID')
|
||||||
""",Map.of("ids",eligible.keySet()),(r,i)->new Object[]{
|
""",Map.of("ids",eligible.keySet()),(r,i)->new Object[]{
|
||||||
new Bill(r.getLong("id"),r.getLong("tenant_id"),r.getString("bill_no"),r.getString("currency_code")),r.getLong("source_id")});
|
new Bill(r.getLong("id"),r.getLong("tenant_id"),r.getString("bill_no"),r.getString("currency_code")),r.getLong("source_id")});
|
||||||
var bills=new LinkedHashMap<Long,Bill>();var byFee=new HashMap<Long,Set<Long>>();
|
var bills=new LinkedHashMap<Long,Bill>();var byFee=new HashMap<Long,Set<Long>>();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"title": "车次Finance权威应收与实收只读来源",
|
"title": "车次Finance权威应收与实收只读来源",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Lastleg以不可变DEPART验证后的客户/派送业务号读取。仅本Finance库;最新已审核有效LASTLEG OVERSEAS_DELIVERY_FEE应收,按币种。实收只取fin_receipt_bill已确认分配;整张ISSUED账单全部来源均明确归属请求车次时才计一次。混合账单、无分配、无有效来源为待分配,不按账单总额或比例估算。最多200业务、2000费用,批量查询。现行应收结算单收款沿关联账单,fin_settlement_payment仅用于应付,不重复叠加。"
|
"description": "Lastleg以不可变DEPART验证后的客户/派送业务号读取。仅本Finance库;最新已审核有效LASTLEG OVERSEAS_DELIVERY_FEE应收,按币种。实收只取fin_receipt_bill已确认分配;整张已出账账单(ISSUED、PARTIALLY_PAID、PAID)全部来源均明确归属请求车次时才计一次。混合账单、无分配、无有效来源为待分配,不按账单总额或比例估算。最多200业务、2000费用,批量查询。现行应收结算单收款沿关联账单,fin_settlement_payment仅用于应付,不重复叠加。"
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/internal/finance/v1/trip-receivables/query": {
|
"/internal/finance/v1/trip-receivables/query": {
|
||||||
|
|||||||
@@ -35,17 +35,46 @@ class TripFinanceQueryServiceTest {
|
|||||||
assertThat(result.totals().get(0).receivableAmount()).isEqualByComparingTo("20");
|
assertThat(result.totals().get(0).receivableAmount()).isEqualByComparingTo("20");
|
||||||
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("ATTRIBUTED");
|
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("ATTRIBUTED");
|
||||||
}
|
}
|
||||||
|
@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);
|
||||||
|
String amount="PAID".equals(status)?"20":"3.5";receipt(amount);
|
||||||
|
jdbc.update("UPDATE fin_bill SET status=?",status);
|
||||||
|
var result=service.query(request(true));
|
||||||
|
assertThat(result.documents()).as(status).hasSize(1);
|
||||||
|
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("ATTRIBUTED");
|
||||||
|
assertThat(result.totals().get(0).receivedAmount()).as(status).isEqualByComparingTo(amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test void draftPendingApprovedAndVoidedBillsNeverContributeReceipts() {
|
||||||
|
for(String status:List.of("DRAFT","PENDING_REVIEW","APPROVED","VOIDED")) {
|
||||||
|
setup();fee(1,1,"DL-A",1,"CNY","20","AVAILABLE");bill(1,1);receipt("3.5");
|
||||||
|
jdbc.update("UPDATE fin_bill SET status=?",status);
|
||||||
|
var result=service.query(request(true));assertThat(result.documents()).as(status).isEmpty();
|
||||||
|
assertThat(result.totals().get(0).receivedAmount()).isNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test void paidBillStillEnforcesCustomerVersionAndCurrencyAttribution() {
|
||||||
|
for(String change:List.of("source_version=2","tenant_id=2","currency_code='USD'")) {
|
||||||
|
setup();fee(1,1,"DL-A",1,"CNY","20","AVAILABLE");bill(1,1);receipt("20");
|
||||||
|
jdbc.update("UPDATE fin_bill SET status='PAID'");jdbc.update("UPDATE fin_bill_line SET "+change);
|
||||||
|
assertThat(service.query(request(true)).totals().get(0).receivedAmount()).as(change).isNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
@Test void mixedBillNeverProratesReceipt() {
|
@Test void mixedBillNeverProratesReceipt() {
|
||||||
fee(1,1,"DL-A",1,"CNY","20","AVAILABLE");bill(1,1);receipt("30");
|
fee(1,1,"DL-A",1,"CNY","20","AVAILABLE");bill(1,1);receipt("30");
|
||||||
jdbc.update("INSERT INTO fin_bill_line VALUES(1,1,999,1,'CNY')");
|
jdbc.update("INSERT INTO fin_bill_line VALUES(1,1,999,1,'CNY')");
|
||||||
|
jdbc.update("UPDATE fin_bill SET status='PAID'");
|
||||||
var result=service.query(request(true));assertThat(result.totals().get(0).receivedAmount()).isNull();
|
var result=service.query(request(true));assertThat(result.totals().get(0).receivedAmount()).isNull();
|
||||||
|
assertThat(result.documents()).hasSize(1);
|
||||||
assertThat(result.documents().get(0).billNo()).isEqualTo("BILL-A");
|
assertThat(result.documents().get(0).billNo()).isEqualTo("BILL-A");
|
||||||
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("PENDING_ALLOCATION");
|
assertThat(result.documents().get(0).allocationStatus()).isEqualTo("PENDING_ALLOCATION");
|
||||||
}
|
}
|
||||||
@Test void unbilledOrNoConfirmedReceiptIsUnknownNotZero() {
|
@Test void unbilledOrNoConfirmedReceiptIsUnknownNotZero() {
|
||||||
fee(1,1,"DL-A",1,"CNY","0","AVAILABLE");
|
fee(1,1,"DL-A",1,"CNY","0","AVAILABLE");
|
||||||
assertThat(service.query(request(true)).totals().get(0).receivedAmount()).isNull();
|
assertThat(service.query(request(true)).totals().get(0).receivedAmount()).isNull();
|
||||||
bill(1,1);assertThat(service.query(request(true)).totals().get(0).receivedAmount()).isNull();
|
bill(1,1);var unpaid=service.query(request(true));assertThat(unpaid.totals().get(0).receivedAmount()).isNull();
|
||||||
|
assertThat(unpaid.documents()).hasSize(1);assertThat(unpaid.documents().get(0).allocationStatus()).isEqualTo("PENDING_ALLOCATION");
|
||||||
assertThat(service.query(request(true)).totals().get(0).receivableAmount()).isEqualByComparingTo("0");
|
assertThat(service.query(request(true)).totals().get(0).receivableAmount()).isEqualByComparingTo("0");
|
||||||
}
|
}
|
||||||
@Test void latestVoidedDoesNotFallBackAndOtherCustomerExcluded() {
|
@Test void latestVoidedDoesNotFallBackAndOtherCustomerExcluded() {
|
||||||
|
|||||||
Reference in New Issue
Block a user