package com.sinata.appointment.service; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import cn.dev33.satoken.stp.StpUtil; import com.sinata.appointment.constants.ApprovalInstanceStatus; import com.sinata.appointment.constants.ApprovalTaskStatus; import com.sinata.appointment.dto.ApprovalActionRequest; import com.sinata.appointment.entity.AppointmentOrder; import com.sinata.appointment.entity.ApprovalInstance; import com.sinata.appointment.entity.ApprovalTask; import com.sinata.appointment.mapper.AppointmentOrderMapper; import com.sinata.appointment.mapper.ApprovalInstanceMapper; import com.sinata.appointment.mapper.ApprovalTaskMapper; import com.sinata.appointment.service.event.AppointmentApprovedEvent; import com.sinata.appointment.service.event.AppointmentRejectedEvent; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.context.ApplicationEventPublisher; @ExtendWith(MockitoExtension.class) class ApprovalApplicationServiceTest { @Mock private ApprovalTaskMapper approvalTaskMapper; @Mock private ApprovalInstanceMapper approvalInstanceMapper; @Mock private AppointmentOrderMapper appointmentOrderMapper; @Mock private ApprovalEngineService approvalEngineService; @Mock private ApplicationEventPublisher applicationEventPublisher; @InjectMocks private ApprovalApplicationService approvalApplicationService; @Test void handleActionRejectPublishesRejectedEvent() { ApprovalTask task = buildTask(); ApprovalInstance instance = buildInstance(200L, ApprovalInstanceStatus.IN_PROGRESS); AppointmentOrder order = buildOrder(200L); ApprovalActionRequest request = new ApprovalActionRequest(); request.setTaskId(100L); request.setTaskUuid("task-uuid"); request.setApprove(false); request.setComment("不同意"); when(approvalTaskMapper.selectById(100L)).thenReturn(task); when(approvalInstanceMapper.selectById(300L)).thenReturn(instance); when(appointmentOrderMapper.selectById(200L)).thenReturn(order); try (MockedStatic mockedStatic = mockStatic(StpUtil.class)) { mockedStatic.when(StpUtil::getLoginIdAsLong).thenReturn(99L); approvalApplicationService.handleAction(request); } verify(approvalTaskMapper).updateById(task); verify(approvalEngineService).rejectInstance(instance, "不同意"); ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(Object.class); verify(applicationEventPublisher).publishEvent(eventCaptor.capture()); AppointmentRejectedEvent event = (AppointmentRejectedEvent) eventCaptor.getValue(); assertEquals(200L, event.orderId()); assertEquals("不同意", event.reason()); } @Test void handleActionApprovePublishesApprovedEventWhenFlowCompletes() { ApprovalTask task = buildTask(); ApprovalInstance instance = buildInstance(200L, ApprovalInstanceStatus.IN_PROGRESS); ApprovalInstance latest = buildInstance(200L, ApprovalInstanceStatus.APPROVED); AppointmentOrder order = buildOrder(200L); ApprovalActionRequest request = new ApprovalActionRequest(); request.setTaskId(100L); request.setTaskUuid("task-uuid"); request.setApprove(true); request.setComment("通过"); when(approvalTaskMapper.selectById(100L)).thenReturn(task); when(approvalInstanceMapper.selectById(300L)).thenReturn(instance, latest); when(appointmentOrderMapper.selectById(200L)).thenReturn(order); when(approvalEngineService.isCurrentNodeComplete(instance)).thenReturn(true); try (MockedStatic mockedStatic = mockStatic(StpUtil.class)) { mockedStatic.when(StpUtil::getLoginIdAsLong).thenReturn(99L); approvalApplicationService.handleAction(request); } verify(approvalEngineService).markGroupSkippedExcept(task); verify(approvalEngineService).advanceOrComplete(instance, order); ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(Object.class); verify(applicationEventPublisher).publishEvent(eventCaptor.capture()); AppointmentApprovedEvent event = (AppointmentApprovedEvent) eventCaptor.getValue(); assertEquals(200L, event.orderId()); } @Test void handleActionApproveDoesNotPublishEventWhenFlowStillInProgress() { ApprovalTask task = buildTask(); ApprovalInstance instance = buildInstance(200L, ApprovalInstanceStatus.IN_PROGRESS); AppointmentOrder order = buildOrder(200L); ApprovalActionRequest request = new ApprovalActionRequest(); request.setTaskId(100L); request.setTaskUuid("task-uuid"); request.setApprove(true); when(approvalTaskMapper.selectById(100L)).thenReturn(task); when(approvalInstanceMapper.selectById(300L)).thenReturn(instance); when(appointmentOrderMapper.selectById(200L)).thenReturn(order); when(approvalEngineService.isCurrentNodeComplete(instance)).thenReturn(false); try (MockedStatic mockedStatic = mockStatic(StpUtil.class)) { mockedStatic.when(StpUtil::getLoginIdAsLong).thenReturn(99L); approvalApplicationService.handleAction(request); } verify(applicationEventPublisher, never()).publishEvent(any()); } private ApprovalTask buildTask() { ApprovalTask task = new ApprovalTask(); task.setId(100L); task.setUuid("task-uuid"); task.setInstanceId(300L); task.setAssigneeUserId(99L); task.setTaskStatus(ApprovalTaskStatus.PENDING); return task; } private ApprovalInstance buildInstance(Long orderId, String status) { ApprovalInstance instance = new ApprovalInstance(); instance.setId(300L); instance.setOrderId(orderId); instance.setStatus(status); return instance; } private AppointmentOrder buildOrder(Long id) { AppointmentOrder order = new AppointmentOrder(); order.setId(id); return order; } }