package com.ruoyi.asset.service.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.ruoyi.asset.constant.AssetStatus;
import com.ruoyi.asset.constant.BorrowOrderStatus;
import com.ruoyi.asset.domain.AmsAsset;
import com.ruoyi.asset.domain.AmsAssetLocation;
import com.ruoyi.asset.domain.AmsBorrowOrder;
import com.ruoyi.asset.domain.AmsBorrowOrderItem;
import com.ruoyi.asset.domain.AmsWarehouse;
import com.ruoyi.asset.domain.AssetTransitionContext;
import com.ruoyi.asset.mapper.AmsAssetMapper;
import com.ruoyi.asset.mapper.AmsBorrowOrderMapper;
import com.ruoyi.asset.service.IAssetStatusTransitionService;
import com.ruoyi.asset.service.IAmsWarehouseService;
import com.ruoyi.asset.service.IAmsAssetLocationService;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.service.ISysCodeRuleService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysUserService;

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.junit.jupiter.MockitoExtension;

/**
 * 借用归还管理服务层单元测试类
 *
 * 重点验证借出、分批归还申请与确认的核心流转校验，包括升序排序防死锁、脏快照仓位验证及状态联动。
 *
 * @author Yangk
 * @date 2026-06-16
 */
@ExtendWith(MockitoExtension.class)
class AmsBorrowOrderServiceImplTest
{
    @Mock
    private AmsBorrowOrderMapper amsBorrowOrderMapper;

    @Mock
    private AmsAssetMapper amsAssetMapper;

    @Mock
    private ISysCodeRuleService sysCodeRuleService;

    @Mock
    private ISysDeptService sysDeptService;

    @Mock
    private ISysUserService sysUserService;

    @Mock
    private IAssetStatusTransitionService assetStatusTransitionService;

    @Mock
    private IAmsWarehouseService amsWarehouseService;

    @Mock
    private IAmsAssetLocationService amsAssetLocationService;

    @InjectMocks
    private AmsBorrowOrderServiceImpl service;

    /**
     * 测试：新增保存借用单草稿。
     * 断言：
     * 1. 自动生成以 JY 为前缀的单号。
     * 2. 状态初归为 DRAFT。
     * 3. 能够自动快照并回填在库资产的存放仓位属性至明细表。
     */
    @Test
    void insertShouldGenerateCodeAndFillSnapshots()
    {
        AmsBorrowOrder order = buildRequest();
        stubBorrower();        // 模拟借用责任人
        stubStockAsset();      // 模拟资产正处于在库状态

        when(sysCodeRuleService.nextCode("BORROW_ORDER")).thenReturn("JY202606160001");

        doAnswer(invocation -> {
            AmsBorrowOrder inserted = invocation.getArgument(0);
            inserted.setOrderId(100L);
            return 1;
        }).when(amsBorrowOrderMapper).insertAmsBorrowOrder(any(AmsBorrowOrder.class));

        when(amsBorrowOrderMapper.batchAmsBorrowOrderItem(anyList()))
                .thenAnswer(invocation -> ((List<?>) invocation.getArgument(0)).size());

        assertEquals(1, service.insertAmsBorrowOrder(order));

        AmsBorrowOrderItem item = order.getAmsBorrowOrderItemList().get(0);
        assertEquals("JY202606160001", order.getBorrowNo());
        assertEquals(BorrowOrderStatus.DRAFT, order.getOrderStatus());
        assertEquals("WH-001", item.getBeforeWarehouseCode());
        assertEquals("LOC-001", item.getBeforeLocationCode());
        assertEquals(BorrowOrderStatus.BORROWING, item.getReturnStatus());
        assertNotNull(item.getCreateTime());
        assertNull(order.getRejectReason());
    }

    /**
     * 测试：新增草稿时资产已被其他借用单占用。
     * 断言：报错拦截，不执行任何主表写入。
     */
    @Test
    void insertShouldRejectAssetOccupiedByOtherOrder()
    {
        AmsBorrowOrder order = buildRequest();
        stubBorrower();
        stubStockAsset();

        when(sysCodeRuleService.nextCode("BORROW_ORDER")).thenReturn("JY202606160001");

        // 模拟资产已被其他借用单占用
        when(amsBorrowOrderMapper.countOtherActiveBorrowOrderByAssetId(1L, null,
                BorrowOrderStatus.DRAFT, BorrowOrderStatus.PENDING_CONFIRM)).thenReturn(1);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.insertAmsBorrowOrder(order));

        assertTrue(exception.getMessage().contains("已被其他未完成借用单占用"));
        verify(amsBorrowOrderMapper, never()).insertAmsBorrowOrder(any(AmsBorrowOrder.class));
    }

    /**
     * 测试：提交借用单草稿。
     * 断言：单据状态扭转为 PENDING_CONFIRM，且验证前置仓位和占用无异常。
     */
    @Test
    void submitShouldMoveDraftToPendingConfirm()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.DRAFT);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);
        stubStockAsset();
        when(amsBorrowOrderMapper.submitAmsBorrowOrder(any(AmsBorrowOrder.class))).thenReturn(1);

        assertEquals(1, service.submitBorrow(100L, "admin"));

        assertEquals(BorrowOrderStatus.PENDING_CONFIRM, order.getOrderStatus());
        verify(amsBorrowOrderMapper).submitAmsBorrowOrder(order);
    }

    /**
     * 测试：物理仓位发生了改变（脏快照）。
     * 断言：强行阻断并报错，要求撤回重新编辑。
     */
    @Test
    void submitShouldRejectDirtySnapshot()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.DRAFT);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);

        // 模拟物理仓位已被移动 (返回的仓库ID与明细的10L不符)
        AmsAsset asset = new AmsAsset();
        asset.setAssetId(1L);
        asset.setAssetCode("A001");
        asset.setAssetStatus(AssetStatus.IN_STOCK);
        asset.setWarehouseId(99L);
        asset.setLocationId(20L);
        asset.setDelFlag("0");
        when(amsAssetMapper.selectAmsAssetByAssetIdForUpdate(1L)).thenReturn(asset);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.submitBorrow(100L, "admin"));

        assertTrue(exception.getMessage().contains("物理存放仓位已发生变更"));
        verify(amsBorrowOrderMapper, never()).submitAmsBorrowOrder(any(AmsBorrowOrder.class));
    }

    /**
     * 测试：确认借出申请。
     * 断言：调用 confirmBorrow 公共状态流转服务，更新资产，单据进入 BORROWING 状态。
     */
    @Test
    void confirmShouldDelegateTransitionAndCompleteBorrowing()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.PENDING_CONFIRM);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);
        stubStockAsset();
        when(amsBorrowOrderMapper.confirmAmsBorrowOrder(any(AmsBorrowOrder.class))).thenReturn(1);

        assertEquals(1, service.confirmBorrow(100L, 1L, "确认人", "admin"));

        ArgumentCaptor<AssetTransitionContext> contextCaptor = ArgumentCaptor.forClass(AssetTransitionContext.class);
        verify(assetStatusTransitionService).confirmBorrow(
                org.mockito.ArgumentMatchers.eq(1L),
                contextCaptor.capture());

        assertEquals(100L, contextCaptor.getValue().getSourceOrderId());
        assertEquals(101L, contextCaptor.getValue().getSourceItemId());
        assertEquals(BorrowOrderStatus.BORROWING, order.getOrderStatus());
        assertEquals("确认人", order.getConfirmUserName());
    }

    /**
     * 测试：申请归还（可分批）。
     * 断言：明细状态置为 PENDING_RETURN_CONFIRM，且联动主表置为 PENDING_RETURN_CONFIRM。
     */
    @Test
    void applyReturnShouldSetStatusAndWarehouse()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.BORROWING);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderItemByOrderIdAndItemIdForUpdate(100L, 101L))
                .thenReturn(buildBorrowItem(BorrowOrderStatus.BORROWING));

        // 模拟处于借出状态下的资产
        AmsAsset asset = new AmsAsset();
        asset.setAssetId(1L);
        asset.setAssetCode("A001");
        asset.setAssetStatus(AssetStatus.BORROWED);
        asset.setDelFlag("0");
        when(amsAssetMapper.selectAmsAssetByAssetIdForUpdate(1L)).thenReturn(asset);

        // 模拟要归还的目标仓位
        AmsWarehouse wh = new AmsWarehouse();
        wh.setWarehouseId(10L);
        wh.setWarehouseCode("WH-001");
        wh.setWarehouseName("一号仓");
        wh.setEnabled("Y");
        when(amsWarehouseService.selectAmsWarehouseByWarehouseId(10L)).thenReturn(wh);

        AmsAssetLocation loc = new AmsAssetLocation();
        loc.setLocationId(20L);
        loc.setLocationCode("LOC-001");
        loc.setLocationName("货架01");
        loc.setWarehouseId(10L);
        loc.setEnabled("Y");
        when(amsAssetLocationService.selectAmsAssetLocationByLocationId(20L)).thenReturn(loc);

        // 模拟更新明细和主单状态
        when(amsBorrowOrderMapper.updateAmsBorrowOrderItemReturnStatus(any(AmsBorrowOrderItem.class),
                org.mockito.ArgumentMatchers.eq(BorrowOrderStatus.BORROWING))).thenReturn(1);
        when(amsBorrowOrderMapper.updateAmsBorrowOrderStatus(
                org.mockito.ArgumentMatchers.eq(100L),
                org.mockito.ArgumentMatchers.eq(BorrowOrderStatus.PENDING_RETURN_CONFIRM),
                any(), any())).thenReturn(1);

        // 构造归还申请明细参数
        List<AmsBorrowOrderItem> applyList = new ArrayList<>();
        AmsBorrowOrderItem applyItem = new AmsBorrowOrderItem();
        applyItem.setItemId(101L);
        applyItem.setAssetId(999L);
        applyItem.setReturnWarehouseId(10L);
        applyItem.setReturnLocationId(20L);
        applyList.add(applyItem);

        assertEquals(1, service.applyReturn(100L, applyList, "admin"));

        // 验证快照正确回填
        ArgumentCaptor<AmsBorrowOrderItem> itemCaptor = ArgumentCaptor.forClass(AmsBorrowOrderItem.class);
        verify(amsBorrowOrderMapper).updateAmsBorrowOrderItemReturnStatus(itemCaptor.capture(),
                org.mockito.ArgumentMatchers.eq(BorrowOrderStatus.BORROWING));
        assertEquals(1L, itemCaptor.getValue().getAssetId());
        assertEquals("WH-001", itemCaptor.getValue().getReturnWarehouseCode());
        assertEquals("LOC-001", itemCaptor.getValue().getReturnLocationCode());
        assertEquals(BorrowOrderStatus.PENDING_RETURN_CONFIRM, itemCaptor.getValue().getReturnStatus());
        verify(amsAssetMapper).selectAmsAssetByAssetIdForUpdate(1L);
        verify(amsAssetMapper, never()).selectAmsAssetByAssetIdForUpdate(999L);
    }

    /**
     * 测试：归还申请的明细不属于当前借用单。
     * 断言：必须在锁明细阶段阻断，不得继续锁资产或更新明细。
     */
    @Test
    void applyReturnShouldRejectItemNotBelongToOrder()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.BORROWING);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderItemByOrderIdAndItemIdForUpdate(100L, 999L))
                .thenReturn(null);

        AmsBorrowOrderItem applyItem = new AmsBorrowOrderItem();
        applyItem.setItemId(999L);
        applyItem.setReturnWarehouseId(10L);
        applyItem.setReturnLocationId(20L);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.applyReturn(100L, Collections.singletonList(applyItem), "admin"));

        assertTrue(exception.getMessage().contains("归还明细不存在"));
        verify(amsAssetMapper, never()).selectAmsAssetByAssetIdForUpdate(any());
        verify(amsBorrowOrderMapper, never()).updateAmsBorrowOrderItemReturnStatus(any(), any());
    }

    /**
     * 测试：确认归还（单据内所有明细都已归还完毕）。
     * 断言：资产回归 IN_STOCK 且回位仓位，主表扭转为 BORROW_RETURNED。
     */
    @Test
    void confirmReturnShouldCompleteOrderIfAllReturned()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.PENDING_RETURN_CONFIRM);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderItemByOrderIdAndItemIdForUpdate(100L, 101L))
                .thenReturn(buildPendingReturnItem());

        AmsAsset asset = new AmsAsset();
        asset.setAssetId(1L);
        asset.setAssetCode("A001");
        asset.setAssetStatus(AssetStatus.BORROWED);
        asset.setDelFlag("0");
        when(amsAssetMapper.selectAmsAssetByAssetIdForUpdate(1L)).thenReturn(asset);

        when(amsBorrowOrderMapper.updateAmsBorrowOrderItemReturnStatus(any(AmsBorrowOrderItem.class),
                org.mockito.ArgumentMatchers.eq(BorrowOrderStatus.PENDING_RETURN_CONFIRM))).thenReturn(1);

        // 模拟查询明细列表
        List<AmsBorrowOrderItem> details = new ArrayList<>();
        AmsBorrowOrderItem detailItem = new AmsBorrowOrderItem();
        detailItem.setItemId(101L);
        detailItem.setAssetId(1L);
        detailItem.setReturnWarehouseId(10L);
        detailItem.setReturnLocationId(20L);
        // 这里模拟这行在确认后变成了已归还
        detailItem.setReturnStatus(BorrowOrderStatus.BORROW_RETURNED);
        details.add(detailItem);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderItemList(100L)).thenReturn(details);

        when(amsBorrowOrderMapper.updateAmsBorrowOrderStatus(
                org.mockito.ArgumentMatchers.eq(100L),
                org.mockito.ArgumentMatchers.eq(BorrowOrderStatus.BORROW_RETURNED),
                any(), any())).thenReturn(1);

        // 构造确认归还明细参数
        List<AmsBorrowOrderItem> confirmList = new ArrayList<>();
        AmsBorrowOrderItem confirmItem = new AmsBorrowOrderItem();
        confirmItem.setItemId(101L);
        confirmItem.setAssetId(999L);
        confirmItem.setReturnWarehouseId(99L);
        confirmItem.setReturnLocationId(98L);
        confirmList.add(confirmItem);

        assertEquals(1, service.confirmReturn(100L, confirmList, 1L, "确认人", "admin"));

        // 验证执行了公共状态流转服务 confirmBorrowReturn
        verify(assetStatusTransitionService).confirmBorrowReturn(
                org.mockito.ArgumentMatchers.eq(1L),
                org.mockito.ArgumentMatchers.eq(10L),
                org.mockito.ArgumentMatchers.eq(20L),
                any(AssetTransitionContext.class));
        verify(amsAssetMapper).selectAmsAssetByAssetIdForUpdate(1L);
        verify(amsAssetMapper, never()).selectAmsAssetByAssetIdForUpdate(999L);
    }

    /**
     * 测试：部分确认归还完毕，但还有的在借出中。
     * 断言：单据主单状态降级退回到 BORROWING 借用中。
     */
    @Test
    void confirmReturnShouldKeepBorrowingIfPartiallyReturned()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.PENDING_RETURN_CONFIRM);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderItemByOrderIdAndItemIdForUpdate(100L, 101L))
                .thenReturn(buildPendingReturnItem());

        AmsAsset asset = new AmsAsset();
        asset.setAssetId(1L);
        asset.setAssetCode("A001");
        asset.setAssetStatus(AssetStatus.BORROWED);
        asset.setDelFlag("0");
        when(amsAssetMapper.selectAmsAssetByAssetIdForUpdate(1L)).thenReturn(asset);

        when(amsBorrowOrderMapper.updateAmsBorrowOrderItemReturnStatus(any(AmsBorrowOrderItem.class),
                org.mockito.ArgumentMatchers.eq(BorrowOrderStatus.PENDING_RETURN_CONFIRM))).thenReturn(1);

        // 模拟该借用单有两行，一行已归还，另一行仍是 BORROWING（借出状态中）
        List<AmsBorrowOrderItem> details = new ArrayList<>();
        AmsBorrowOrderItem detailItem1 = new AmsBorrowOrderItem();
        detailItem1.setItemId(101L);
        detailItem1.setAssetId(1L);
        detailItem1.setReturnStatus(BorrowOrderStatus.BORROW_RETURNED);
        details.add(detailItem1);

        AmsBorrowOrderItem detailItem2 = new AmsBorrowOrderItem();
        detailItem2.setItemId(102L);
        detailItem2.setAssetId(2L);
        detailItem2.setReturnStatus(BorrowOrderStatus.BORROWING);
        details.add(detailItem2);

        when(amsBorrowOrderMapper.selectAmsBorrowOrderItemList(100L)).thenReturn(details);

        // 此时主表状态联动退回到 BORROWING
        when(amsBorrowOrderMapper.updateAmsBorrowOrderStatus(
                org.mockito.ArgumentMatchers.eq(100L),
                org.mockito.ArgumentMatchers.eq(BorrowOrderStatus.BORROWING),
                any(), any())).thenReturn(1);

        List<AmsBorrowOrderItem> confirmList = new ArrayList<>();
        AmsBorrowOrderItem confirmItem = new AmsBorrowOrderItem();
        confirmItem.setItemId(101L);
        confirmList.add(confirmItem);

        assertEquals(1, service.confirmReturn(100L, confirmList, 1L, "确认人", "admin"));
    }

    /**
     * 测试：待归还确认明细缺少已保存的归还仓位。
     * 断言：确认阶段不能采信前端重新传入的仓位，必须阻断。
     */
    @Test
    void confirmReturnShouldRejectMissingStoredReturnLocation()
    {
        AmsBorrowOrder order = buildPersistedOrder(BorrowOrderStatus.PENDING_RETURN_CONFIRM);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderByOrderIdForUpdate(100L)).thenReturn(order);

        AmsBorrowOrderItem lockedItem = buildBorrowItem(BorrowOrderStatus.PENDING_RETURN_CONFIRM);
        lockedItem.setReturnWarehouseId(null);
        lockedItem.setReturnLocationId(null);
        when(amsBorrowOrderMapper.selectAmsBorrowOrderItemByOrderIdAndItemIdForUpdate(100L, 101L))
                .thenReturn(lockedItem);

        AmsBorrowOrderItem confirmItem = new AmsBorrowOrderItem();
        confirmItem.setItemId(101L);
        confirmItem.setReturnWarehouseId(10L);
        confirmItem.setReturnLocationId(20L);

        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.confirmReturn(100L, Collections.singletonList(confirmItem),
                        1L, "确认人", "admin"));

        assertTrue(exception.getMessage().contains("缺少已申请的归还仓库或位置"));
        verify(assetStatusTransitionService, never()).confirmBorrowReturn(any(), any(), any(), any());
        verify(amsBorrowOrderMapper, never()).updateAmsBorrowOrderItemReturnStatus(any(), any());
    }

    private AmsBorrowOrder buildRequest()
    {
        AmsBorrowOrder order = new AmsBorrowOrder();
        order.setBorrowUserId(2L);
        order.setBorrowDeptId(103L);

        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, 5); // 5天后
        order.setExpectedReturnDate(cal.getTime());
        order.setRemark("测试借用单");

        List<AmsBorrowOrderItem> itemList = new ArrayList<>();
        AmsBorrowOrderItem item = new AmsBorrowOrderItem();
        item.setAssetId(1L);
        itemList.add(item);
        order.setAmsBorrowOrderItemList(itemList);

        return order;
    }

    private AmsBorrowOrder buildPersistedOrder(String status)
    {
        AmsBorrowOrder order = buildRequest();
        order.setOrderId(100L);
        order.setBorrowNo("JY202606160001");
        order.setOrderStatus(status);
        order.setBorrowUserName("借用用户");
        order.setBorrowDeptName("生产部门");

        AmsBorrowOrderItem item = order.getAmsBorrowOrderItemList().get(0);
        item.setItemId(101L);
        item.setBorrowNo("JY202606160001");
        item.setBeforeWarehouseId(10L);
        item.setBeforeLocationId(20L);

        return order;
    }

    private AmsBorrowOrderItem buildBorrowItem(String returnStatus)
    {
        AmsBorrowOrderItem item = new AmsBorrowOrderItem();
        item.setItemId(101L);
        item.setOrderId(100L);
        item.setBorrowNo("JY202606160001");
        item.setAssetId(1L);
        item.setAssetCode("A001");
        item.setAssetName("一号资产");
        item.setBeforeWarehouseId(10L);
        item.setBeforeWarehouseCode("WH-001");
        item.setBeforeWarehouseName("一号仓");
        item.setBeforeLocationId(20L);
        item.setBeforeLocationCode("LOC-001");
        item.setBeforeLocationName("货架01");
        item.setReturnStatus(returnStatus);
        item.setDelFlag("0");
        return item;
    }

    private AmsBorrowOrderItem buildPendingReturnItem()
    {
        AmsBorrowOrderItem item = buildBorrowItem(BorrowOrderStatus.PENDING_RETURN_CONFIRM);
        item.setReturnWarehouseId(10L);
        item.setReturnWarehouseCode("WH-001");
        item.setReturnWarehouseName("一号仓");
        item.setReturnLocationId(20L);
        item.setReturnLocationCode("LOC-001");
        item.setReturnLocationName("货架01");
        return item;
    }

    private void stubBorrower()
    {
        SysUser user = new SysUser();
        user.setUserId(2L);
        user.setUserName("借用用户");
        user.setDeptId(103L);
        user.setStatus("0");
        user.setDelFlag("0");
        when(sysUserService.selectUserById(2L)).thenReturn(user);

        SysDept dept = new SysDept();
        dept.setDeptId(103L);
        dept.setDeptName("生产部门");
        dept.setStatus("0");
        dept.setDelFlag("0");
        when(sysDeptService.selectDeptById(103L)).thenReturn(dept);
    }

    private void stubStockAsset()
    {
        AmsAsset asset = new AmsAsset();
        asset.setAssetId(1L);
        asset.setAssetCode("A001");
        asset.setAssetName("一号资产");
        asset.setCategoryId(5L);
        asset.setCategoryCode("CAT-001");
        asset.setCategoryName("类别一");
        asset.setWarehouseId(10L);
        asset.setWarehouseCode("WH-001");
        asset.setWarehouseName("一号仓");
        asset.setLocationId(20L);
        asset.setLocationCode("LOC-001");
        asset.setLocationName("货架01");
        asset.setAssetStatus(AssetStatus.IN_STOCK);
        asset.setDelFlag("0");

        when(amsAssetMapper.selectAmsAssetByAssetIdForUpdate(1L)).thenReturn(asset);
    }
}
