# HkInventoryPurchaseOrderController.java

    package cloud.wconnect.workperformance.controller.hkinventory;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.cons.hkinventory.HkInventoryErrorI18nConstant;
    import cloud.wconnect.workperformance.cons.hkinventory.StatusEnum;
    import cloud.wconnect.workperformance.entity.hkinventory.*;
    import cloud.wconnect.workperformance.pojo.dto.hkinventory.HkInventoryPurchaseOrderDTO;
    import cloud.wconnect.workperformance.pojo.query.hkinventory.HkInventoryPurchaseOrderQuery;
    import cloud.wconnect.workperformance.pojo.vo.hkinventory.HkInventoryPurchaseOrderVO;
    import cloud.wconnect.workperformance.service.hkinventory.*;
    import com.google.common.collect.ImmutableMap;
    import jakarta.validation.Valid;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.web.bind.annotation.*;

    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.YearMonth;
    import java.util.Collections;
    import java.util.Map;
    import java.util.Objects;

    /**
     * 采购单控制层
     *
     * @author lichen
     * @date 2025/4/23
     */
    @RestController
    @RequestMapping("/hk-inventory/purchase-order")
    public class HkInventoryPurchaseOrderController {

        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private IHkInventoryPurchaseOrderService purchaseOrderService;
        @Autowired
        private IHkInventoryItemConfigService itemConfigService;
        @Autowired
        private IHkInventoryCategoryConfigService categoryConfigService;
        @Autowired
        private IHkInventoryRoomTypeConfigService roomTypeConfigService;
        @Autowired
        @Lazy
        private IHkInventoryService hkInventoryService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 分页查询采购单
         *
         * @param property                      资产标识
         * @param hkInventoryPurchaseOrderQuery 查询参数
         * @return cloud.wconnect.commonlib.pojo.dto.ListPagedDTO<cloud.wconnect.workperformance.pojo.vo.hkinventory.HkInventoryPurchaseOrderVO>
         * @author lichen
         * @date 2025/4/23
         */
        @ApiId(1428)
        @GetMapping
        public ListPagedDTO<HkInventoryPurchaseOrderVO> pageList(String property, @Valid HkInventoryPurchaseOrderQuery hkInventoryPurchaseOrderQuery) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);

            Long startPurchaseTime = hkInventoryPurchaseOrderQuery.getStartPurchaseTime();
            Long endPurchaseTime = hkInventoryPurchaseOrderQuery.getEndPurchaseTime();
            //开始时间不能大于结束时间
            if (startPurchaseTime > endPurchaseTime) {
                throw new BadRequestException(CommonErrorI18nConstant.START_DATE_CANNOT_GREATER_THAN_END_DATE,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The endPurchaseTime must be greater than or equal to the startPurchaseTime");
            }
            //判断时间间隔必须小于3个月（后端判断93天）
            long diffDay = DateTimeUtils.dateDiffOfDays(startPurchaseTime, endPurchaseTime, propertyDTO.getTimezone());
            if (Math.abs(diffDay) > 93) {
                throw new BadRequestException(CommonErrorI18nConstant.SELECT_DATE_LIMIT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("93"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The interval between fromDate and toDate must be less than or equal to 93 days");
            }

            return purchaseOrderService.pageList(propertyDTO, hkInventoryPurchaseOrderQuery);
        }

        /**
         * 保存采购单
         *
         * @param property         资产标识
         * @param purchaseOrderId  采购单id
         * @param purchaseOrderDTO 采购单DTO
         * @return java.util.Map<java.lang.String, java.lang.Integer>
         * @author lichen
         * @date 2025/4/23
         */
        @ApiId(1429)
        @PostMapping("/{purchaseOrderId:\\d+}")
        public Map<String, Integer> save(String property, @PathVariable Integer purchaseOrderId, @RequestBody @Valid HkInventoryPurchaseOrderDTO purchaseOrderDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            int loginUserId = sessionContext.getLoginUserId();

            //查询最近发布的客房库存管理
            HkInventory recentPublishedData = hkInventoryService.listRecentPublished(propertyDTO.getId());
            if (Objects.nonNull(recentPublishedData)) {
                YearMonth yearMonth = YearMonth.of(recentPublishedData.getYear(), recentPublishedData.getMonth());
                //获取下个月的第一天
                LocalDate nextMonthFirstDay = yearMonth.atEndOfMonth().plusDays(1);
                long nextMonthFirstDayLong = DateTimeUtils.localDateToLong(nextMonthFirstDay, propertyDTO.getTimezone());
                //购买时间只能在资产已发布的月份以后
                if (purchaseOrderDTO.getPurchaseTime() < nextMonthFirstDayLong) {
                    throw new BadRequestException(HkInventoryErrorI18nConstant.PURCHASE_TIME_MUST_GREATER_THAN_PUBLISHED_INVENTORY_MONTH,
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The purchase time can only be after the month when the property has been released");
                }
            } else {
                //获取2个月前第一天
                LocalDateTime localDateTime = LocalDate.now().minusMonths(2).withDayOfMonth(1).atStartOfDay();
                //购买日期不能小于2个月前第一天
                if (purchaseOrderDTO.getPurchaseTime() < DateTimeUtils.localDateTimeToTimestamp(localDateTime, propertyDTO.getTimezone())) {
                    throw new BadRequestException(HkInventoryErrorI18nConstant.PURCHASE_TIME_CANNOT_LESS_THAN_FIRST_DAY_OF_TWO_MONTHS_AGO,
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "The purchase time cannot be less than the first day of last month");
                }
            }

            if (purchaseOrderId > 0) {
                //校验采购单是否存在
                HkInventoryPurchaseOrder oriHkInventoryPurchaseOrder = purchaseOrderService.checkExist(purchaseOrderId);
                //校验采购单是否归属于当前资产
                purchaseOrderService.checkBelongProperty(oriHkInventoryPurchaseOrder, propertyDTO.getId());
                //校验客房库存管理是否待发布状态
                checkHkInventoryStatus(propertyDTO, oriHkInventoryPurchaseOrder);
                //校验不可修改的字段
                checkUnmodifiableFields(oriHkInventoryPurchaseOrder, purchaseOrderDTO);
                //修改
                purchaseOrderService.update(propertyId, oriHkInventoryPurchaseOrder, purchaseOrderDTO, loginUserId);
                return ImmutableMap.of("id", purchaseOrderId);
            } else {
                //校验item是否存在
                HkInventoryItemConfig itemConfig = itemConfigService.checkExist(purchaseOrderDTO.getItemId());
                //校验item是否归属于当前资产
                itemConfigService.checkBelongProperty(itemConfig, propertyDTO.getId());
                //校验item是否归属于房型
                itemConfigService.checkBelongRoomType(itemConfig, purchaseOrderDTO.getRoomTypeId());
                //校验item是否归属于分类
                itemConfigService.checkBelongCategory(itemConfig, purchaseOrderDTO.getCategoryId());
                purchaseOrderDTO.setItemName(itemConfig.getItemName());

                //校验房型是否存在
                HkInventoryRoomTypeConfig roomTypeConfig = roomTypeConfigService.checkExist(purchaseOrderDTO.getRoomTypeId());
                //校验房型是否归属于资产
                roomTypeConfigService.checkBelongProperty(roomTypeConfig, propertyDTO.getId());
                purchaseOrderDTO.setRoomTypeName(roomTypeConfig.getRoomTypeName());

                //校验分类是否存在
                HkInventoryCategoryConfig categoryConfig = categoryConfigService.checkExist(purchaseOrderDTO.getCategoryId());
                //校验分类是否属于当前资产
                categoryConfigService.checkBelong(categoryConfig, propertyDTO.getId());
                //校验分类配置是否包含指定房型
                categoryConfigService.checkContainRoomType(categoryConfig, purchaseOrderDTO.getRoomTypeId());
                purchaseOrderDTO.setCategoryName(categoryConfig.getCategoryName());

                return ImmutableMap.of("id", purchaseOrderService.insert(propertyDTO, purchaseOrderDTO, loginUserId));
            }
        }

        /**
         * 删除采购单
         *
         * @param property        资产标识
         * @param purchaseOrderId 采购单id
         * @return java.util.Map<java.lang.String, java.lang.String>
         * @author lichen
         * @date 2025/4/25
         */
        @ApiId(1430)
        @DeleteMapping("/{purchaseOrderId:\\d+}")
        public Map<String, String> delete(String property, @PathVariable Integer purchaseOrderId) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //校验采购单是否存在
            HkInventoryPurchaseOrder oriHkInventoryPurchaseOrder = purchaseOrderService.checkExist(purchaseOrderId);
            //校验采购单是否归属于当前资产
            purchaseOrderService.checkBelongProperty(oriHkInventoryPurchaseOrder, propertyDTO.getId());
            //校验客房库存管理是否待发布状态
            checkHkInventoryStatus(propertyDTO, oriHkInventoryPurchaseOrder);
            //删除采购单
            purchaseOrderService.removeById(purchaseOrderId);
            return Collections.emptyMap();
        }

        /**
         * 校验不可修改的字段
         *
         * @param oriHkInventoryPurchaseOrder 修改前的采购单
         * @param purchaseOrderDTO            修改后的采购单DTO
         * @return void
         * @author lichen
         * @date 2025/4/23
         */
        private void checkUnmodifiableFields(HkInventoryPurchaseOrder oriHkInventoryPurchaseOrder, HkInventoryPurchaseOrderDTO purchaseOrderDTO) {
            //校验分类id不可修改
            if (!oriHkInventoryPurchaseOrder.getCategoryId().equals(purchaseOrderDTO.getCategoryId())) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_MODIFIED,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("categoryId"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "categoryId cannot be modified");
            }
            //校验房型id不可修改
            if (!oriHkInventoryPurchaseOrder.getRoomTypeId().equals(purchaseOrderDTO.getRoomTypeId())) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_MODIFIED,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("roomTypeId"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "roomTypeId cannot be modified");
            }
            //校验item id不可修改
            if (!oriHkInventoryPurchaseOrder.getItemId().equals(purchaseOrderDTO.getItemId())) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_MODIFIED,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("itemId"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "itemId cannot be modified");
            }
        }

        /**
         * 校验客房库存管理是否待发布状态
         *
         * @param propertyDTO   资产DTO
         * @param purchaseOrder 采购单
         * @return void
         * @author lichen
         * @date 2025/4/25
         */
        private void checkHkInventoryStatus(PropertyDTO propertyDTO, HkInventoryPurchaseOrder purchaseOrder) {
            //购买日期对应的年、月
            LocalDate localDate = DateTimeUtils.longToLocalDate(purchaseOrder.getPurchaseTime(), propertyDTO.getTimezone());
            int year = localDate.getYear();
            int monthValue = localDate.getMonthValue();

            //获取资产指定月份的Housekeeping Inventory
            HkInventory hkInventory = hkInventoryService.getByYearMonth(propertyDTO.getId(), year, monthValue);
            if (Objects.nonNull(hkInventory)) {
                //校验客房库存管理必须是待发布状态
                hkInventoryService.checkStatusMustBe(hkInventory.getStatus(), StatusEnum.PENDING.getStatus());

            }
        }

    }