# BudgetDatabaseConfigRoomTabController.java

    package cloud.wconnect.rateshop.controller.budgetdatabase;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.jsonview.Views;
    import cloud.wconnect.rateshop.cons.budgetdatabase.BudgetDatabaseErrorCons;
    import cloud.wconnect.rateshop.cons.budgetdatabase.ClassificationCons;
    import cloud.wconnect.rateshop.cons.budgetdatabase.RoomClassificationEnum;
    import cloud.wconnect.rateshop.cons.budgetdatabase.VariableTypeEnum;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigRoomTab;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigRoomTabItem;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.*;
    import cloud.wconnect.rateshop.pojo.query.budgetdatabase.ConfigItemQuery;
    import cloud.wconnect.rateshop.service.budgetdatabase.*;
    import com.fasterxml.jackson.annotation.JsonView;
    import com.google.common.collect.ImmutableMap;
    import jakarta.validation.Valid;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;

    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;

    /**
     * <p>
     *  前端控制器
     * </p>
     *
     * @author yyt
     * @since 2025-11-10
     */
    @RestController
    @RequestMapping("/budget-database")
    public class BudgetDatabaseConfigRoomTabController {

        @Autowired
        private IBudgetDatabaseService budgetDatabaseService;
        @Autowired
        private IBudgetDatabaseConfigRoomTabService budgetDatabaseConfigRoomTabService;
        @Autowired
        private IBudgetDatabaseConfigRoomTabItemService budgetDatabaseConfigRoomTabItemService;
        @Autowired
        private IBudgetDatabaseConfigVariableService budgetDatabaseConfigVariableService;
        @Autowired
        private IBudgetDatabaseConfigVariableRoomService budgetDatabaseConfigVariableRoomService;
        @Autowired
        private IBudgetDatabaseCheckCircularDependencyService budgetDatabaseCheckCircularDependencyService;
        @Autowired
        private SessionContext sessionContext;

        /**
         * 1624 - 获取所有 tab
         *
         * @param year     年
         * @param property 资产标识
         * @return tab
         * @author yyt
         * @date 2025/11/10
         **/
        @ApiId(1624)
        @GetMapping("/{year:\\d+}/room-tab")
        public List<TabDTO> list(@PathVariable int year, String property) {
            return budgetDatabaseConfigRoomTabService.listDTOs(sessionContext.getPropertyId(property), year);
        }

        /**
         * 1625 - 新增/编辑 tab
         *
         * @param year       年
         * @param id         tab id
         * @param property   资产标识
         * @param saveTabDTO tab 信息
         * @return tab id
         * @author yyt
         * @date 2025/11/10
         **/
        @ApiId(1625)
        @PostMapping("/{year:\\d+}/room-tab/{id:\\d+}")
        public Map<String, Integer> saveTab(@PathVariable int year, @PathVariable int id, String property, @Valid @RequestBody SaveTabDTO saveTabDTO) {
            int propertyId = sessionContext.getPropertyId(property);

            // budget database 完成后，则不支持任何操作
            budgetDatabaseService.checkComplete(propertyId, year);

            if (id == BaseConstant.ZERO) {
                // 验重
                budgetDatabaseConfigRoomTabService.checkRepeat(propertyId, year, saveTabDTO.getName(), null);

                // 验证 tab 数量最多不可超过5个
                budgetDatabaseConfigRoomTabService.checkTabCount(propertyId, year);

                // 保存
                return ImmutableMap.of("id", budgetDatabaseConfigRoomTabService.save(propertyId, year, saveTabDTO, sessionContext.getLoginUserId()));
            } else {
                // 验证 tab 存在
                BudgetDatabaseConfigRoomTab tab = budgetDatabaseConfigRoomTabService.checkExist(id);

                // 验证资产所属
                budgetDatabaseConfigRoomTabService.checkBelong(tab, propertyId);

                // 验重
                budgetDatabaseConfigRoomTabService.checkRepeat(propertyId, year, saveTabDTO.getName(), id);

                // 更新
                budgetDatabaseConfigRoomTabService.update(id, saveTabDTO, sessionContext.getLoginUserId());

                return ImmutableMap.of("id", id);
            }
        }

        /**
         * 1554 - 查询配置
         *
         * @param tabId    tab id
         * @param property 资产标识
         * @param query    查询条件
         * @return 配置列表
         * @author yyt
         * @date 2025/11/10
         */
        @JsonView(Views.DetailsView.class)
        @ApiId(1554)
        @GetMapping("/{tabId:\\d+}/room-config")
        public ListPagedDTO<ConfigItemDTO> list(@PathVariable int tabId, String property, ConfigItemQuery query) {
            Integer propertyId = sessionContext.getPropertyId(property);
            return budgetDatabaseConfigRoomTabItemService.list(propertyId, tabId, query);
        }

        /**
         * 1555 - 保存配置
         *
         * @param tabId               tab id
         * @param id                  数据 id
         * @param property            资产标识
         * @param updateConfigItemDTO 配置
         * @return {}
         * @author yyt
         * @date 2025/11/10
         */
        @ApiId(1555)
        @PostMapping("/{tabId:\\d+}/room-config/{id:\\d+}")
        public RoomConfigBoundToDTO save(@PathVariable int tabId, @PathVariable int id, String property, @Valid @RequestBody UpdateRoomConfigItemDTO updateConfigItemDTO) {
            Integer propertyId = sessionContext.getPropertyId(property);

            // budget database 完成后，则不支持任何操作
            budgetDatabaseService.checkComplete(propertyId, budgetDatabaseConfigRoomTabService.getById(tabId).getBudgetYear());

            // other 分类不支持开启 room
            if (Objects.equals(updateConfigItemDTO.getClassification(), RoomClassificationEnum.OTHER.getCode()) && updateConfigItemDTO.getEnableBudgetRoom()) {
                throw new BadRequestException(BudgetDatabaseErrorCons.ENABLE_ROOM_FORMULA_FAIL,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "Cannot enable room number formula calculation.");
            }

            // 验证变量配置
            if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                // 验证存在
                budgetDatabaseConfigVariableService.checkExist(propertyId, VariableTypeEnum.REVENUE.getCode(), updateConfigItemDTO.getBudgetRevenueVariableId());
            }
            if (updateConfigItemDTO.getEnableBudgetRoom()) {
                budgetDatabaseConfigVariableService.checkExist(propertyId, VariableTypeEnum.ROOM.getCode(), updateConfigItemDTO.getBudgetRoomVariableId());
            }

            BudgetDatabaseConfigRoomTab tab = budgetDatabaseConfigRoomTabService.checkTab(tabId, propertyId);
            Integer budgetYear = tab.getBudgetYear();

            if (id == BaseConstant.ZERO) {
                budgetDatabaseConfigRoomTabItemService.checkRepeat(propertyId, tabId, updateConfigItemDTO.getClassification(), updateConfigItemDTO.getType(), updateConfigItemDTO.getName(), null);

                budgetDatabaseConfigRoomTabItemService.save(tab, updateConfigItemDTO, sessionContext.getLoginUserId());

                return new RoomConfigBoundToDTO();
            } else {
                RoomConfigBoundToDTO roomConfigBoundToDTO = new RoomConfigBoundToDTO();

                budgetDatabaseConfigRoomTabItemService.checkRepeat(propertyId, tabId, updateConfigItemDTO.getClassification(), updateConfigItemDTO.getType(), updateConfigItemDTO.getName(), id);

                BudgetDatabaseConfigRoomTabItem config = budgetDatabaseConfigRoomTabItemService.checkExist(id);

                budgetDatabaseConfigRoomTabItemService.checkBelong(config, propertyId);

                // 验证当前变量配置是否绑定过当前配置
                boolean boundToRevenue = false;
                boolean boundToRoom = false;
                boolean revenueCircularDependency = false;
                boolean roomCircularDependency = false;
                if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                    boundToRevenue = budgetDatabaseConfigVariableRoomService.checkBoundToTheConfig(propertyId, updateConfigItemDTO.getBudgetRevenueVariableId(), config.getId());
                    revenueCircularDependency = budgetDatabaseCheckCircularDependencyService.checkCircularDependency(propertyId, budgetYear, updateConfigItemDTO.getBudgetRevenueVariableId(),
                            StringUtils.joinWith(":", ClassificationCons.ROOM, config.getId()), VariableTypeEnum.REVENUE.getCode());
                }
                if (updateConfigItemDTO.getEnableBudgetRoom()) {
                    boundToRoom = budgetDatabaseConfigVariableRoomService.checkBoundToTheConfig(propertyId, updateConfigItemDTO.getBudgetRoomVariableId(), config.getId());
                    roomCircularDependency = budgetDatabaseCheckCircularDependencyService.checkCircularDependency(propertyId, budgetYear, updateConfigItemDTO.getBudgetRoomVariableId(),
                            StringUtils.joinWith(":", ClassificationCons.ROOM, config.getId()), VariableTypeEnum.ROOM.getCode());
                }
                if (boundToRevenue || boundToRoom || revenueCircularDependency || roomCircularDependency) {
                    roomConfigBoundToDTO.setBoundToRevenue(boundToRevenue);
                    roomConfigBoundToDTO.setBoundToRoom(boundToRoom);
                    roomConfigBoundToDTO.setRevenueCircularDependency(revenueCircularDependency);
                    roomConfigBoundToDTO.setRoomCircularDependency(roomCircularDependency);
                    return roomConfigBoundToDTO;
                }

                budgetDatabaseConfigRoomTabItemService.update(tab, config, updateConfigItemDTO, sessionContext.getLoginUserId());

                return roomConfigBoundToDTO;
            }
        }

        /**
         * 1556 - 删除配置
         *
         * @param id       数据 id
         * @param property 资产标识
         * @return 可以删除标志
         * @author yyt
         * @date 2025/11/11
         */
        @ApiId(1556)
        @DeleteMapping("/room-config/{id:\\d+}")
        public ConfigDeleteFlagDTO delete(@PathVariable int id, String property) {
            Integer propertyId = sessionContext.getPropertyId(property);
            BudgetDatabaseConfigRoomTabItem config = budgetDatabaseConfigRoomTabItemService.checkExist(id);

            budgetDatabaseConfigRoomTabItemService.checkBelong(config, propertyId);

            // budget database 完成后，则不支持任何操作
            BudgetDatabaseConfigRoomTab roomTab = budgetDatabaseConfigRoomTabService.getById(config.getRoomTabId());
            budgetDatabaseService.checkComplete(propertyId, roomTab.getBudgetYear());

            // 若被变量配置引用到，则不可删除
            if (budgetDatabaseConfigVariableRoomService.checkConfigBoundToTheVariable(propertyId, config.getId())) {
                return new ConfigDeleteFlagDTO(false, true);
            }

            if (Objects.equals(config.getClassification(), RoomClassificationEnum.OTHER.getCode())) {
                return new ConfigDeleteFlagDTO(budgetDatabaseConfigRoomTabItemService.handleDeleteOtherConfig(config), false);
            } else {
                return new ConfigDeleteFlagDTO(budgetDatabaseConfigRoomTabItemService.handleDeleteRoomConfig(config), false);
            }
        }

        /**
         * 1626 - 参与计算 Total Revenue
         *
         * @param id                   tab id
         * @param participateCalculate 参与计算标志
         * @param property             资产标识
         * @return {}
         * @author yyt
         * @date 2025/11/11
         **/
        @ApiId(1626)
        @PutMapping("/room-tab/{id:\\d+}/participate-calculate/{participateCalculate}")
        public Map participateCalculateTotalRevenue(@PathVariable int id, @PathVariable boolean participateCalculate, String property) {
            BudgetDatabaseConfigRoomTab roomTab = budgetDatabaseConfigRoomTabService.checkExist(id);
            budgetDatabaseConfigRoomTabService.checkBelong(roomTab, sessionContext.getPropertyId(property));

            budgetDatabaseConfigRoomTabService.participateCalculate(id, participateCalculate, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 1627 - 删除 tab
         *
         * @param  id tab id
         * @param property 资产标识
         * @return 配置删除标志
         * @author yyt
         * @date 2025/11/11
         **/
        @ApiId(1627)
        @DeleteMapping("/room-tab/{id:\\d+}")
        public ConfigDeleteFlagDTO deleteRoomTab(@PathVariable int id, String property) {
            BudgetDatabaseConfigRoomTab roomTab = budgetDatabaseConfigRoomTabService.checkExist(id);
            budgetDatabaseConfigRoomTabService.checkBelong(roomTab, sessionContext.getPropertyId(property));
            return budgetDatabaseConfigRoomTabService.handleDelete(roomTab);
        }

    }