package com.tourguide.modules.finance.service; import com.alibaba.fastjson.JSONObject; import com.tourguide.common.huifu.biz.DouGongWithdrawBiz; import com.tourguide.common.huifu.biz.FenZhangUtil; import com.tourguide.modules.finance.entity.GuideWithdrawal; import com.tourguide.modules.finance.entity.GuideWithdrawalAccount; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class GuideWithdrawalPayoutServiceTest { private GuideWithdrawalStateService stateService; private GuideSettlementService settlementService; private FenZhangUtil fenZhangUtil; private DouGongWithdrawBiz withdrawBiz; private GuideWithdrawalPayoutService service; @BeforeEach void setUp() { stateService = mock(GuideWithdrawalStateService.class); settlementService = mock(GuideSettlementService.class); fenZhangUtil = mock(FenZhangUtil.class); withdrawBiz = mock(DouGongWithdrawBiz.class); service = new GuideWithdrawalPayoutService( stateService, settlementService, fenZhangUtil, withdrawBiz); } @Test void approveShouldTransferFromPlatformBeforeSubmittingCash() throws Exception { GuideWithdrawal transferring = withdrawal("TRANSFERRING"); transferring.setTransferReqSeqId("TF001"); transferring.setTransferReqDate("20260817"); GuideWithdrawal cash = withdrawal("PROCESSING"); cash.setCashReqSeqId("CW001"); cash.setCashReqDate("20260817"); GuideWithdrawalAccount account = account(); when(stateService.prepareTransfer(20L, null, "admin")).thenReturn(transferring); when(stateService.prepareCash(20L)).thenReturn(cash); when(stateService.find(20L)).thenReturn(cash); when(settlementService.requireApprovedCard(8L, 10)).thenReturn(account); Map transferResponse = new HashMap<>(); transferResponse.put("resp_code", "00000000"); transferResponse.put("trans_stat", "S"); transferResponse.put("hf_seq_id", "HF-TF-1"); when(fenZhangUtil.fenzhang("TF001", "20260817", "200.00", "HF100")) .thenReturn(transferResponse); JSONObject cashResponse = new JSONObject(); cashResponse.put("resp_code", "00000100"); cashResponse.put("resp_desc", "受理成功"); when(withdrawBiz.encashment(new BigDecimal("200.00"), "HF100", "TOKEN100", "CW001", "20260817")).thenReturn(cashResponse); service.approve(20L, null, "admin"); verify(stateService).markTransferred(20L, "HF-TF-1"); verify(withdrawBiz).encashment(new BigDecimal("200.00"), "HF100", "TOKEN100", "CW001", "20260817"); } @Test void transferFailureShouldNeverSubmitCash() throws Exception { GuideWithdrawal transferring = withdrawal("TRANSFERRING"); transferring.setTransferReqSeqId("TF001"); transferring.setTransferReqDate("20260817"); when(stateService.prepareTransfer(20L, null, "admin")).thenReturn(transferring); when(stateService.find(20L)).thenReturn(transferring); when(settlementService.requireApprovedCard(8L, 10)).thenReturn(account()); Map response = new HashMap<>(); response.put("resp_code", "100001"); response.put("resp_desc", "主账户余额不足"); when(fenZhangUtil.fenzhang("TF001", "20260817", "200.00", "HF100")) .thenReturn(response); service.approve(20L, null, "admin"); verify(stateService).markTransferFailed(20L, "主账户划账失败:主账户余额不足"); verify(withdrawBiz, never()).encashment( org.mockito.ArgumentMatchers.any(), anyString(), anyString(), anyString(), anyString()); } @Test void transferredRecordWithCashSequenceShouldQueryOriginalRequestInsteadOfResubmitting() { GuideWithdrawal transferred = withdrawal("TRANSFERRED"); transferred.setCashReqSeqId("CW001"); transferred.setCashReqDate("20260818"); GuideWithdrawal processing = withdrawal("PROCESSING"); processing.setCashReqSeqId("CW001"); processing.setCashReqDate("20260818"); when(stateService.find(20L)).thenReturn(transferred); when(stateService.resumeCashQuery(20L)).thenReturn(processing); when(settlementService.requireApprovedCard(8L, 10)).thenReturn(account()); JSONObject queryResponse = new JSONObject(); queryResponse.put("resp_code", "00000000"); queryResponse.put("trans_stat", "S"); when(withdrawBiz.query("HF100", "20260818", "CW001")).thenReturn(queryResponse); service.advance(20L); verify(stateService).resumeCashQuery(20L); verify(withdrawBiz).query("HF100", "20260818", "CW001"); verify(withdrawBiz, never()).encashment(any(), anyString(), anyString(), anyString(), anyString()); verify(stateService).markApproved(20L, null); } @Test void cashQueryBusinessErrorShouldRemainProcessing() { GuideWithdrawal processing = withdrawal("PROCESSING"); processing.setCashReqSeqId("CW001"); processing.setCashReqDate("20260818"); when(stateService.find(20L)).thenReturn(processing); when(settlementService.requireApprovedCard(8L, 10)).thenReturn(account()); JSONObject queryResponse = new JSONObject(); queryResponse.put("resp_code", "20000100"); queryResponse.put("resp_desc", "查询服务暂不可用"); when(withdrawBiz.query("HF100", "20260818", "CW001")).thenReturn(queryResponse); service.advance(20L); verify(stateService).markCashPending(20L, null, "导游账户取现查询失败:查询服务暂不可用"); verify(stateService, never()).markCashRetry(any(), anyString()); } private GuideWithdrawal withdrawal(String status) { GuideWithdrawal withdrawal = new GuideWithdrawal(); withdrawal.setId(20L); withdrawal.setGuideId(8L); withdrawal.setBankCardId(10); withdrawal.setAmount(new BigDecimal("200.00")); withdrawal.setStatus(status); return withdrawal; } private GuideWithdrawalAccount account() { GuideWithdrawalAccount account = new GuideWithdrawalAccount(); account.setHuifuId("HF100"); account.setTokenNo("TOKEN100"); return account; } }