verou
2025-04-10 4d9b73a4e5acf3f3b97ebbdb69154c704bb3077d
Merge branch 'devlop' of http://47.97.1.152:5880/r/wms-master into devlop
13个文件已修改
5个文件已删除
968 ■■■■ 已修改文件
rsf-admin/src/page/ResourceContent.js 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrderLog/AsnOrderLogEdit.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrderLog/AsnOrderLogList.jsx 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/task/TaskEdit.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/taskItemLog/TaskItemLogCreate.jsx 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/taskItemLog/TaskItemLogEdit.jsx 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/taskItemLog/TaskItemLogList.jsx 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/taskItemLog/TaskItemLogPanel.jsx 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/taskItemLog/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/taskLog/TaskItemLogList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/MobileController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/MobileService.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/MobileServiceImpl.java 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderItemLog.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/TaskItemLog.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/QlyInspectServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/service/UserService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/UserServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/ResourceContent.js
@@ -45,11 +45,11 @@
import waitPakinLog from './waitPakinLog';
import waitPakinItemLog from './waitPakinItemLog';
import asnOrderLog from './asnOrderLog';
import asnOrderItemLog from './asnOrderItemLog';
// import asnOrderItemLog from './asnOrderItemLog';
import task from './task';
// import taskItem from './taskItem';
import taskLog from './taskLog';
import taskItemLog from './taskItemLog';
// import taskItemLog from './taskItemLog';
const ResourceContent = (node) => {
@@ -110,8 +110,8 @@
            return asnOrderItem;
        case 'asnOrderLog':
            return asnOrderLog;
        case 'asnOrderItemLog':
            return asnOrderItemLog;
        // case 'asnOrderItemLog':
        //     return asnOrderItemLog;
        case 'purchaseItem':
            return purchaseItem;
        case 'purchase':
@@ -144,8 +144,8 @@
        //     return taskItem;
        case 'taskLog':
            return taskLog;
        case 'taskItemLog':
            return taskItemLog;
        // case 'taskItemLog':
        //     return taskItemLog;
        default:
            return {
rsf-admin/src/page/asnOrderLog/AsnOrderLogEdit.jsx
@@ -21,21 +21,20 @@
    DeleteButton,
} from 'react-admin';
import { useWatch, useFormContext } from "react-hook-form";
import { Stack, Grid, Box, Typography } from '@mui/material';
import { Stack, Grid, Box, Typography, Card } from '@mui/material';
import * as Common from '@/utils/common';
import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
import EditBaseAside from "../components/EditBaseAside";
import CustomerTopToolBar from "../components/EditTopToolBar";
import MemoInput from "../components/MemoInput";
import StatusSelectInput from "../components/StatusSelectInput";
import AsnOrderItemLogList from "./AsnOrderItemLogList"
const FormToolbar = () => {
    const { getValues } = useFormContext();
    return (
        <Toolbar sx={{ justifyContent: 'space-between' }}>
        <Toolbar sx={{ justifyContent: 'end' }}>
            <SaveButton />
            <DeleteButton mutationMode="optimistic" />
        </Toolbar>
    )
}
@@ -44,6 +43,7 @@
    const translate = useTranslate();
    return (
        <>
        <Edit
            redirect="list"
            mutationMode={EDIT_MODE}
@@ -59,7 +59,7 @@
            // validate={(values) => { }}
            >
                <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
                    <Grid item xs={12} md={8}>
                        <Grid item xs={24} md={12}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.main')}
                        </Typography>
@@ -68,34 +68,30 @@
                                label="table.field.asnOrderLog.code"
                                source="code"
                                parse={v => v}
                                autoFocus
                                    readOnly
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.asnOrderLog.poCode"
                                source="poCode"
                                    readOnly
                                parse={v => v}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.asnOrderLog.poId"
                                    readOnly
                                source="poId"
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.asnOrderLog.type"
                                source="type"
                                    readOnly
                                parse={v => v}
                                validate={required()}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.asnOrderLog.wkType"
                                source="wkType"
                                    readOnly
                                parse={v => v}
                                validate={required()}
                            />
@@ -104,44 +100,30 @@
                            <NumberInput
                                label="table.field.asnOrderLog.anfme"
                                source="anfme"
                                    readOnly
                                validate={required()}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.asnOrderLog.qty"
                                source="qty"
                                    readOnly
                                validate={required()}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.asnOrderLog.logisNo"
                                source="logisNo"
                                    readOnly
                                parse={v => v}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <DateInput
                                label="table.field.asnOrderLog.arrTime"
                                    readOnly
                                source="arrTime"
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <SelectInput
                                label="table.field.asnOrderLog.rleStatus"
                                source="rleStatus"
                                choices={[
                                    { id: 0, name: ' 正常' },
                                    { id:  1, name: ' 已释放' },
                                ]}
                                validate={required()}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <SelectInput
                                label="table.field.asnOrderLog.ntyStatus"
                                source="ntyStatus"
                                    readOnly
                                choices={[
                                    { id: 0, name: ' 未上报' },
                                    { id:  1, name: ' 已上报' },
@@ -150,19 +132,17 @@
                                validate={required()}
                            />
                        </Stack>
                    </Grid>
                    <Grid item xs={12} md={4}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.common')}
                        </Typography>
                        <StatusSelectInput />
                        <Box mt="2em" />
                        <MemoInput />
                    </Grid>
                </Grid>
            </SimpleForm>
        </Edit >
            <Grid item xs={24} md={16} sx={{ marginTop: '1em' }}>
                <Typography variant="h6" gutterBottom >
                    {translate('common.edit.title.common')}
                </Typography>
            </Grid>
            <AsnOrderItemLogList />
        </>
    )
}
rsf-admin/src/page/asnOrderLog/AsnOrderLogList.jsx
@@ -31,8 +31,6 @@
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
    useRefresh,
    Button,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
@@ -45,7 +43,6 @@
import MyField from "../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import ReplayIcon from '@mui/icons-material/Replay';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
@@ -57,7 +54,7 @@
    '& .column-name': {
    },
    '& .opt': {
        width: 300
        width: 200
    },
}));
@@ -101,7 +98,6 @@
const AsnOrderLogList = () => {
    const translate = useTranslate();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
@@ -123,7 +119,7 @@
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        {/* <MyCreateButton onClick={() => { setCreateDialog(true) }} /> */}
                        <SelectColumnsButton preferenceKey='asnOrderLog' />
                        <MyExportButton />
                    </TopToolbar>
@@ -133,8 +129,8 @@
                <StyledDatagrid
                    preferenceKey='asnOrderLog'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <AsnOrderLogPanel />}
                    rowClick={'edit'}
                    expand={false}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
@@ -161,11 +157,6 @@
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
                        <RecoverButton />
                    </WrapperField>
                </StyledDatagrid>
            </List>
            <AsnOrderLogCreate
@@ -183,25 +174,3 @@
}
export default AsnOrderLogList;
const RecoverButton = () => {
    const record = useRecordContext();
    const notify = useNotify();
    const refresh = useRefresh();
    const requestRecover = async () => {
        const { data: { code, data, msg } } = await request.post(`/asnOrder/recover/${record.id}`);
        if (code === 200) {
            notify(msg);
            refresh()
        } else {
            notify(msg);
        }
    }
    return (
        (<Button onClick={requestRecover} label={"toolbar.recover"} color="success">
            <ReplayIcon />
        </Button>)
    )
}
rsf-admin/src/page/task/TaskEdit.jsx
@@ -107,14 +107,12 @@
                    </Grid>
                </SimpleForm>
            </Edit >
            <Card sx={{ marginTop: '1em', }}>
                <Grid item xs={24} md={16} sx={{ margin: '1em' }}>
            <Grid item xs={24} md={16} sx={{ margin: '1em', height: 'auto' }}>
                    <Typography variant="h6" gutterBottom >
                        {translate('common.edit.title.common')}
                    </Typography>
                    <TaskItemList />
                </Grid>
            </Card>
            <TaskItemList />
        </>
    )
}
rsf-admin/src/page/taskItemLog/TaskItemLogCreate.jsx
File was deleted
rsf-admin/src/page/taskItemLog/TaskItemLogEdit.jsx
File was deleted
rsf-admin/src/page/taskItemLog/TaskItemLogList.jsx
File was deleted
rsf-admin/src/page/taskItemLog/TaskItemLogPanel.jsx
File was deleted
rsf-admin/src/page/taskItemLog/index.jsx
File was deleted
rsf-admin/src/page/taskLog/TaskItemLogList.jsx
@@ -31,6 +31,7 @@
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
    useGetRecordId,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
@@ -88,13 +89,15 @@
const TaskItemLogList = () => {
    const translate = useTranslate();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    const recodeId = useGetRecordId();
    return (
        <Box display="flex">
            <List
                resource="taskItemLog"
                sx={{
                    flexGrow: 1,
                    transition: (theme) =>
@@ -106,6 +109,7 @@
                title={"menu.taskItemLog"}
                filters={filters}
                empty={false}
                filter={{logId: Number(recodeId) }}
                sort={{ field: "create_time", order: "desc" }}
                actions={(
                    <TopToolbar>
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/MobileController.java
@@ -16,6 +16,7 @@
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -130,6 +131,16 @@
        return mobileService.getDeltByCode(code);
    }
    @PreAuthorize("hasAuthority('manager:asnOrderItem:list')")
    @ApiOperation("获取拖盘明细")
    @PostMapping("/asnOrderItem/container")
    public R getItemByContainer(@RequestBody Map<String, Object> params) {
        if (Objects.isNull(params)) {
            return R.error("参数不能为空!!");
        }
        return mobileService.getItemByContainer(params);
    }
    @PreAuthorize("hasAuthority('manager:waitPakin:update')")
    @ApiOperation("组拖")
    @PostMapping("/waitPakin/merge")
@@ -193,11 +204,11 @@
    }
    @ApiOperation("快带质检")
    @ApiOperation("快速质检")
    @PreAuthorize("hasAuthority('manager:qlyInspect:update')")
    @PostMapping("/inspect/check/update")
    public R checkUpdate(@RequestBody QlyIsptItem params) {
        if (Objects.isNull(params)) {
    public R checkUpdate(@RequestBody List<QlyIsptItem> params) {
        if (Objects.isNull(params) || params.isEmpty()) {
            return R.error("参数不能为空!!");
        }
        return mobileService.checkUpdate(params);
rsf-server/src/main/java/com/vincent/rsf/server/api/service/MobileService.java
@@ -48,7 +48,7 @@
    R checkObjs(CheckObjParams params);
    R checkUpdate(QlyIsptItem params);
    R checkUpdate(List<QlyIsptItem> params);
    R operateToStock(OpStockParams params);
@@ -59,4 +59,6 @@
    R taskGetLocs(String code) throws Exception;
    R completeOrder(Long id, Long loginUserId);
    R getItemByContainer(Map<String, Object> params);
}
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/MobileServiceImpl.java
@@ -22,6 +22,7 @@
import com.vincent.rsf.server.manager.controller.params.WaitPakinParam;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.AsnExceStatus;
import com.vincent.rsf.server.manager.enums.PakinIOStatus;
import com.vincent.rsf.server.manager.mapper.*;
import com.vincent.rsf.server.manager.service.*;
import com.vincent.rsf.server.system.constant.CodeRes;
@@ -34,8 +35,10 @@
import com.vincent.rsf.server.system.mapper.UserMapper;
import com.vincent.rsf.server.system.service.FieldsItemService;
import com.vincent.rsf.server.system.service.UserLoginService;
import com.vincent.rsf.server.system.service.UserService;
import com.vincent.rsf.server.system.utils.ExtendFieldsUtils;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import net.sf.jsqlparser.statement.select.Wait;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -66,7 +69,7 @@
    @Autowired
    private TenantMapper tenantService;
    @Autowired
    private UserMapper userService;
    private UserService userService;
    @Autowired
    private UserLoginService userLoginService;
    @Autowired
@@ -147,7 +150,7 @@
        if (user.getStatus() != 1) {
            return R.parse(CodeRes.USER_10002);
        }
        if (!user.getPassword().equals(param.getPassword())) {
        if (!userService.comparePassword(user.getPassword(), param.getPassword())) {
            return R.parse(CodeRes.USER_10003);
        }
@@ -494,20 +497,18 @@
        if (Objects.isNull(params.getIsptCode())) {
            throw new CoolException("质检单不能为空");
        }
        if (Objects.isNull(params.getMatnrCode())) {
            throw new CoolException("物料编码不能为空!");
        }
        QlyInspect inspect = qlyInspectMapper.selectOne(new LambdaQueryWrapper<QlyInspect>().eq(QlyInspect::getCode, params.getIsptCode()));
        if (Objects.isNull(inspect)) {
            throw new CoolException("质检单据不存在!!");
        }
        QlyIsptItem isptItem = qlyIsptItemService.getOne(new LambdaQueryWrapper<QlyIsptItem>()
                .eq(QlyIsptItem::getMatnrCode, params.getMatnrCode())
        List<QlyIsptItem> isptItems = qlyIsptItemService.list(new LambdaQueryWrapper<QlyIsptItem>()
                .eq(StringUtils.isNotBlank(params.getMatnrCode()), QlyIsptItem::getMatnrCode, StringUtils.isNotBlank(params.getMatnrCode()) ? params.getMatnrCode() : null)
                .eq(QlyIsptItem::getIspectId, inspect.getId()));
        if (Objects.isNull(isptItem)) {
        if (Objects.isNull(isptItems)) {
            throw new CoolException("质检单明细不存在!!");
        }
        List<CheckObjDto> dtos = new ArrayList<>();
        isptItems.forEach(isptItem -> {
        CheckObjDto objDto = new CheckObjDto();
        objDto.setIsptCode(inspect.getCode())
                .setAsnCode(inspect.getAsnCode())
@@ -523,7 +524,9 @@
                .setPicPath(isptItem.getPicPath())
                .setMemo(isptItem.getMemo())
                .setSafeQty(isptItem.getSafeQty());
        return R.ok(objDto);
            dtos.add(objDto);
        });
        return R.ok(dtos);
    }
    /**
@@ -532,14 +535,12 @@
     * @return
     */
    @Override
    public R checkUpdate(QlyIsptItem params) {
        if (Objects.isNull(params.getId())) {
    public R checkUpdate(List<QlyIsptItem> params) {
        if (Objects.isNull(params) || params.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        IsptItemsParams itemsParams = new IsptItemsParams();
        List<QlyIsptItem> items = new ArrayList<>();
        items.add(params);
        itemsParams.setIsptItem(items).setType("0");
        itemsParams.setIsptItem(params).setType("0");
        if (qlyIsptItemService.batchUpdate(itemsParams)) {
            return R.ok();
        } else {
@@ -729,6 +730,40 @@
    }
    /**
     * @author Ryan
     * @description 通过容器获取组拖物料
     * @param
     * @return
     * @time 2025/4/9 16:57
     */
    @Override
    public R getItemByContainer(Map<String, Object> params) {
        List<Short> asList = Arrays.asList(Short.valueOf(PakinIOStatus.PAKIN_IO_STATUS_DONE.val), Short.valueOf(PakinIOStatus.PAKIN_IO_STATUS_DONE.val));
        WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
                .eq(WaitPakin::getBarcode, params.get("barcode").toString())
                .in(WaitPakin::getIoStatus, asList));
        if (Objects.isNull(waitPakin)) {
            return R.ok(new ArrayList<>());
        }
        List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>()
                .eq(WaitPakinItem::getPakinId, waitPakin.getId()));
        if (pakinItems.isEmpty()) {
            return R.ok(new ArrayList<>());
        }
        List<String> list = pakinItems.stream().map(WaitPakinItem::getTrackCode).collect(Collectors.toList());
        LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new QueryWrapper<WarehouseAreasItem>()
                .select("SUM(anfme) as anfme, track_code, asn_code, id, splr_batch, ispt_result, plat_item_id, batch, qty, work_qty, matnr_code, matnr_id, maktx")
                .lambda()
                .in(WarehouseAreasItem::getTrackCode, list)
                .groupBy(WarehouseAreasItem::getSplrBatch,
                        WarehouseAreasItem::getAsnId,
                        WarehouseAreasItem::getAreaId,
                        WarehouseAreasItem::getTrackCode,
                        WarehouseAreasItem::getMatnrId);
        return R.ok(warehouseAreasItemService.list(queryWrapper));
    }
    /**
     * 获取ReceiptDetlsDtos
     */
    private R getAsnOrderItem(List<AsnOrderItem> items) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderItemLog.java
@@ -37,6 +37,8 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("主单ID")
    private Long logId;
    @ApiModelProperty("Item ID")
    private Long asnItemId;
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/TaskItemLog.java
@@ -37,6 +37,9 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("主单ID")
    private Long logId;
    /**
     * 主单ID
     */
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/QlyInspectServiceImpl.java
@@ -106,8 +106,7 @@
    public List<AsnOrder> getUnInspect(Map<String, Object> params) {
        List<AsnOrder> asnOrders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>()
                .eq(AsnOrder::getStatus, 1)
                .eq(!Objects.isNull(params.get("asnCode")), AsnOrder::getCode, !Objects.isNull(params.get("asnCode")) ? params.get("asnCode").toString() : "")
                .eq(AsnOrder::getNtyStatus, 0));
                .eq(!Objects.isNull(params.get("asnCode")) && StringUtils.isNotBlank(params.get("asnCode").toString()), AsnOrder::getCode, StringUtils.isNotBlank(params.get("asnCode").toString()) ? params.get("asnCode").toString() : null));
        return asnOrders;
    }
rsf-server/src/main/java/com/vincent/rsf/server/system/service/UserService.java
@@ -21,4 +21,5 @@
    String encodePassword(String password);
    User selectByUsernameWithoutTenant(String username, Long tenantId);
}
rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/UserServiceImpl.java
@@ -65,4 +65,9 @@
        return password == null ? null : bCryptPasswordEncoder.encode(password);
    }
    @Override
    public User selectByUsernameWithoutTenant(String username, Long tenantId) {
        return baseMapper.selectByUsernameWithoutTenant(username,tenantId);
    }
}