package com.ruoyi.order.service.impl; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TChargingOrderShareRecord; import com.ruoyi.payment.api.vo.IcbcRefundReq; import com.ruoyi.payment.api.vo.IcbcPaymentResp; import com.ruoyi.payment.api.vo.IcbcSubOrderQueryReq; import com.ruoyi.payment.api.vo.IcbcSubOrderRefundReq; import org.junit.jupiter.api.Test; import java.math.BigDecimal; import java.time.LocalDate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; class IcbcAdminFundOperationSupportTest { @Test void rejectsNonIcbcOrder() { TChargingOrder order = paidOrder(); order.setSourceName("ALIPAY"); IllegalArgumentException error = assertThrows(IllegalArgumentException.class, () -> IcbcAdminFundOperationSupport.validateOrder(order)); assertEquals("仅支持工商银行支付订单", error.getMessage()); } @Test void acceptsBankPaidOrderWhenLocalCallbackStatusIsStillPending() { TChargingOrder order = paidOrder(); order.setRechargePaymentStatus(1); IcbcAdminFundOperationSupport.validateIcbcOrder(order); IcbcPaymentResp payment = new IcbcPaymentResp(); payment.setStatus("0"); payment.setRawResponse("{\"returnCode\":0,\"pay_status\":\"0\",\"order_id\":\"231011990056000012345\"}"); assertTrue(IcbcAdminFundOperationSupport.isBankPaid(payment)); } @Test void rejectsBankQueryThatDoesNotConfirmPayment() { IcbcPaymentResp payment = new IcbcPaymentResp(); payment.setStatus("1"); payment.setRawResponse("{\"returnCode\":0,\"pay_status\":\"1\"}"); assertFalse(IcbcAdminFundOperationSupport.isBankPaid(payment)); } @Test void buildsMainOrderRefundFromBusinessOrder() { IcbcRefundReq request = IcbcAdminFundOperationSupport.buildRefundRequest( paidOrder(), new BigDecimal("0.12"), "ICBCADMINREFUND001"); assertEquals("CD202607110001", request.getOutTradeNo()); assertEquals("231011990056000012345", request.getOrderId()); assertEquals("ICBCADMINREFUND001", request.getOutRefundNo()); assertEquals(new BigDecimal("0.12"), request.getRefundAmount()); assertEquals("管理后台工行退款", request.getReason()); } @Test void buildsConsumptionSubOrderQueryFromShareRecord() { IcbcSubOrderQueryReq request = IcbcAdminFundOperationSupport.buildSubOrderQueryRequest( paidOrder(), shareRecord()); assertEquals("2", request.getOrderNoType()); assertEquals("CD202607110001", request.getMerOrderId()); assertEquals("231011990056", request.getPrtiId()); assertEquals("1", request.getQueryType()); assertEquals("ICBCSUB202607110001", request.getMerTrnscSerno()); assertEquals("231011990055", request.getSubPrtiId()); } @Test void buildsSubOrderRefundFromSelectedShareRecord() { IcbcSubOrderRefundReq request = IcbcAdminFundOperationSupport.buildSubOrderRefundRequest( paidOrder(), shareRecord(), new BigDecimal("0.03"), "ICBCSUBREFUND001", "ICBCSUBREFUNDSERIAL001"); assertEquals("CD202607110001", request.getChargingOrderCode()); assertEquals("CD202607110001", request.getSeqNo()); assertEquals("1", request.getBusiType()); assertEquals("231011990056", request.getOriMerId()); assertEquals("2026-07-11", request.getOriTrxDate()); assertEquals("ICBCSUB202607110001", request.getSubOrderId()); assertEquals("231011990055", request.getSubMerId()); assertEquals("2310119900550201", request.getSubMerPrtclNo()); assertEquals(new BigDecimal("0.03"), request.getRefundAmount()); } @Test void buildsLegacySubOrderRefundWithoutStoredOriginalMerchantId() { TChargingOrderShareRecord record = shareRecord(); record.setSeqNo(null); record.setBusiType(null); record.setOriMerId(null); IcbcSubOrderRefundReq request = IcbcAdminFundOperationSupport.buildSubOrderRefundRequest( paidOrder(), record, new BigDecimal("1.90"), "ICBCSUBREFUNDLEGACY", "ICBCSUBREFUNDSERIALLEGACY"); assertEquals("CD202607110001", request.getSeqNo()); assertEquals("1", request.getBusiType()); assertNull(request.getOriMerId()); assertEquals(new BigDecimal("1.90"), request.getRefundAmount()); } @Test void rejectsAmountWithMoreThanTwoDecimalPlaces() { IllegalArgumentException error = assertThrows(IllegalArgumentException.class, () -> IcbcAdminFundOperationSupport.requireAmount(new BigDecimal("0.004"))); assertEquals("操作金额最多保留两位小数", error.getMessage()); } @Test void rejectsDeletedOrUnsuccessfulShareRecord() { TChargingOrderShareRecord deleted = shareRecord(); deleted.setDelFlag(true); IllegalArgumentException deletedError = assertThrows(IllegalArgumentException.class, () -> IcbcAdminFundOperationSupport.buildSubOrderRefundRequest( paidOrder(), deleted, new BigDecimal("0.01"), "REFUND1", "SERIAL1")); assertEquals("分账记录已删除", deletedError.getMessage()); TChargingOrderShareRecord failed = shareRecord(); failed.setOnlineShareStatus("FAIL"); IllegalArgumentException failedError = assertThrows(IllegalArgumentException.class, () -> IcbcAdminFundOperationSupport.buildSubOrderRefundRequest( paidOrder(), failed, new BigDecimal("0.01"), "REFUND2", "SERIAL2")); assertEquals("仅支持已成功的工行分账记录退款", failedError.getMessage()); } @Test void rejectsIncompleteSuccessfulShareRecord() { TChargingOrderShareRecord record = shareRecord(); record.setSubMerPrtclNo(null); IllegalArgumentException error = assertThrows(IllegalArgumentException.class, () -> IcbcAdminFundOperationSupport.buildSubOrderRefundRequest( paidOrder(), record, new BigDecimal("0.01"), "REFUND3", "SERIAL3")); assertEquals("分账记录缺少工行退款参数", error.getMessage()); } @Test void reusesUnknownRefundSerialOnlyForTheSameAmount() { String pending = IcbcAdminFundOperationSupport.buildPendingRefundValue( "ICBCADMINREFUND001", new BigDecimal("0.04")); assertEquals("ICBCADMINREFUND001", IcbcAdminFundOperationSupport.resolveRefundNo( pending, new BigDecimal("0.04"), "ICBCADMINREFUND002")); IllegalArgumentException error = assertThrows(IllegalArgumentException.class, () -> IcbcAdminFundOperationSupport.resolveRefundNo( pending, new BigDecimal("0.03"), "ICBCADMINREFUND003")); assertEquals("上一笔退款结果未知,请按原金额重试", error.getMessage()); } @Test void keepsUnknownRetrySerialUntilAConfirmedSuccess() { assertFalse(IcbcAdminFundOperationSupport.shouldClearPendingRefund(true, "FAIL", true)); assertTrue(IcbcAdminFundOperationSupport.shouldClearPendingRefund(false, "FAIL", true)); assertTrue(IcbcAdminFundOperationSupport.shouldClearPendingRefund(true, "SUCCESS", true)); assertFalse(IcbcAdminFundOperationSupport.shouldClearPendingRefund(false, "FAIL", false)); } private TChargingOrder paidOrder() { TChargingOrder order = new TChargingOrder(); order.setId(100L); order.setCode("CD202607110001"); order.setSourceName("ICBC"); order.setRechargePaymentStatus(2); order.setRechargeSerialNumber("231011990056000012345"); return order; } private TChargingOrderShareRecord shareRecord() { TChargingOrderShareRecord record = new TChargingOrderShareRecord(); record.setId(200L); record.setChargingOrderId(100L); record.setChargingOrderCode("CD202607110001"); record.setPayChannel("ICBC"); record.setDelFlag(false); record.setOnlineShareStatus("SUCCESS"); record.setSeqNo("CD202607110001"); record.setBusiType("1"); record.setOriMerId("231011990056"); record.setOriTrxDate(LocalDate.of(2026, 7, 11)); record.setSubOrderId("ICBCSUB202607110001"); record.setSubMerId("231011990055"); record.setSubMerPrtclNo("2310119900550201"); return record; } }