package cn.iocoder.yudao.module.system.service.biz;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.api.bpm.BpmCheckInApi;
import cn.iocoder.yudao.module.system.api.bpm.vo.CheckInContractReqVO;
import cn.iocoder.yudao.module.system.api.bpm.vo.CheckInExpenseSaveReqVO;
import cn.iocoder.yudao.module.bpm.api.business.BpmBusinessFormApi;
import cn.iocoder.yudao.module.bpm.api.business.dto.BpmBusinessFormCreateReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ElderlyFixedExpenseAppendReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ExpenseRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ExpenseSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.*;
import cn.iocoder.yudao.module.system.dal.dataobject.reservation.ReservationBedDO;
import cn.iocoder.yudao.module.system.dal.dataobject.reservation.ReservationDepositDO;
import cn.iocoder.yudao.module.system.dal.mysql.biz.*;
import cn.iocoder.yudao.module.system.dal.mysql.reservation.ReservationBedMapper;
import cn.iocoder.yudao.module.system.dal.mysql.reservation.ReservationDepositMapper;
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.system.enums.change.BusinessConstants;
import cn.iocoder.yudao.module.system.enums.common.BooleanEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.Gson;
import com.mzt.logapi.starter.annotation.LogRecord;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exceptionCustomMsg;
import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;


/**
 * 长者费用记录 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class ExpenseServiceImpl implements ExpenseService {

    @Resource
    private ExpenseMapper expenseMapper;
    @Resource
    private ExpenseItemMapper expenseItemMapper;
    @Resource
    private ElderlyInfoMapper elderlyInfoMapper;
    @Resource
    private BalanceService balanceService;

    @Resource
    private ExpenseOrderMapper expenseOrderMapper;
    @Resource
    private ExpenseOrderItemMapper expenseOrderItemMapper;
    @Resource
    private DepositMapper depositMapper;

    @Resource
    private BuildBedMapper buildBedMapper;

    @Resource
    private ElderlyCheckInRecordMapper elderlyCheckInRecordMapper;

    @Resource
    private NurseLevelMapper nurseLevelMapper;
    @Resource
    private BuildService buildService;
    @Resource
    private BuildRoomMapper buildRoomMapper;
    @Resource
    private ElderlyContractMapper elderlyContractMapper;
    @Resource
    private ElderlyContractDetailMapper elderlyContractDetailMapper;
    @Resource
    private DailyExpensesMapper dailyExpensesMapper;
    @Resource
    private ExpenseSubsidyMapper expenseSubsidyMapper;
    @Resource
    private ElderlyConsumerVouchersMapper elderlyConsumerVouchersMapper;

    @Autowired
    private CheckInApplyMapper checkInApplyMapper;

    @Autowired
    private ElderlyCheckInRecordMapper recordMapper;

    @Resource
    private BpmBusinessFormApi bpmBusinessFormApi;

    @Autowired
    private ReservationBedMapper reservationBedMapper;

    @Autowired
    private ReservationDepositMapper reservationDepositMapper;

    @Autowired
    private SysChargeCategoryMapper sysChargeCategoryMapper;


    @Override
    @Transactional
    @LogRecord(type = ELDERLY_CHECK_IN_TYPE, subType = ELDERLY_CHECK_IN_CREATE_SUB_TYPE, bizNo = "{{#elderId}}",
            success = ELDERLY_CHECK_IN_CREATE_SUCCESS, extra = "{{#elderId}}")
    public Long createExpense(ExpenseSaveReqVO createReqVO) {
        List<ExpenseItemDO> monthlyExpenses = createReqVO.getMonthlyExpenses();
        List<ExpenseItemDO> oneTimeExpenses = createReqVO.getOneTimeExpenses();
        List<ExpenseItemDO> stageExpenses = createReqVO.getStageExpenses();
        List<SysChargeCategoryDO> sysChargeCategoryDOS = sysChargeCategoryMapper.selectList(new LambdaQueryWrapperX<SysChargeCategoryDO>().eq(SysChargeCategoryDO::getTenantId, TenantContextHolder.getTenantId()));
        Map<Long, SysChargeCategoryDO> categoryMap = sysChargeCategoryDOS
                .stream()
                .collect(Collectors.toMap(SysChargeCategoryDO::getId, Function.identity()));
        ExpenseDO expense = new ExpenseDO();
        BeanUtils.copyProperties(createReqVO, expense);
        expense.setCreatedTime(new Date());
        expense.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        expenseMapper.insert(expense);


        List<ElderlyContractDO> elderlyContractList = elderlyContractMapper.selectList(new LambdaQueryWrapperX<ElderlyContractDO>().eq(ElderlyContractDO::getElderId, createReqVO.getElderId())
                .orderByDesc(ElderlyContractDO::getCreatedTime));

        //更新合同与费用绑定关系
        if (CollectionUtil.isNotEmpty(elderlyContractList)){
            ElderlyContractDO elderlyContractDO = elderlyContractList.get(0);
            expense.setContractId(elderlyContractDO.getId());
            expenseMapper.updateById(expense);
        }

        Long elderId = createReqVO.getElderId();
        // TODO 绑定床位信息
        ElderlyInfoDO elderlyInfo = elderlyInfoMapper.selectById(createReqVO.getElderId());
        if (elderlyInfo != null && createReqVO.getInStatusType() != null) {
            elderlyInfo.setInStatusType(createReqVO.getInStatusType());
            elderlyInfoMapper.updateById(elderlyInfo);
        }
//        if (elderlyInfo != null) {
//            BuildBedDO bedDO = buildBedMapper.selectById(createReqVO.getBedId());
//            if (bedDO != null) {
//                elderlyInfo.setRoomId(bedDO.getRoomId());
//                elderlyInfo.setFloorId(bedDO.getFloorId());
//                elderlyInfo.setBuildId(bedDO.getBuildId());
//
//                bedDO.setStatus(1);
//                buildBedMapper.updateById(bedDO);
//
//                BuildRoomDO roomDO = buildRoomMapper.selectById(bedDO.getRoomId());
//                roomDO.setStatus(1);
//                buildRoomMapper.updateById(roomDO);
//            }
//            elderlyInfo.setInStatus(1);
//            elderlyInfo.setBedId(createReqVO.getBedId());
//            elderlyInfo.setCheckInTime(createReqVO.getCheckInTime());
//            elderlyInfo.setNurseLevelId(createReqVO.getNurseLevelId());
//            elderlyInfo.setIsPrivateRoom(createReqVO.getIsPrivateRoom());
//            NurseLevelDO nurseLevelDO = nurseLevelMapper.selectById(createReqVO.getNurseLevelId());
//            elderlyInfo.setNurseLevelName(nurseLevelDO == null ? null : nurseLevelDO.getNurseLevelName());
//            elderlyInfoMapper.updateById(elderlyInfo);
//
//            ElderlyCheckInRecordDO elderlyCheckInRecord = elderlyCheckInRecordMapper.selectOne(new LambdaQueryWrapperX<ElderlyCheckInRecordDO>()
//                    .eq(ElderlyCheckInRecordDO::getElderId, elderlyInfo.getId())
//                    .orderByDesc(ElderlyCheckInRecordDO::getCreatedTime)
//                    .last("LIMIT 1"));
//            if (elderlyCheckInRecord != null) {
//                elderlyCheckInRecord.setStatus(2); //修改状态为已入住
//                elderlyCheckInRecord.setCheckInTime(createReqVO.getCheckInTime());
//                elderlyCheckInRecordMapper.updateById(elderlyCheckInRecord);
//            }
//
//            LogRecordContext.putVariable("elderId", elderlyInfo.getId());
//            LogRecordContext.putVariable("elderName", elderlyInfo.getElderName());
//
//        }

        //生成入院缴费账单
        LocalDate date = createReqVO.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate monthEnd = date.with(TemporalAdjusters.lastDayOfMonth());
        long daysUntilMonthEnd = ChronoUnit.DAYS.between(date, monthEnd) + 1; //天数

        ExpenseOrderDO expenseBill = new ExpenseOrderDO();
        expenseBill.setBillingMonth(date.format(DateTimeFormatter.ofPattern("yyyy-MM")));
        expenseBill.setCreatedTime(new Date());
        expenseBill.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        expenseBill.setElderId(createReqVO.getElderId());
        expenseBill.setBillOrderNumber("E" + RandomUtil.randomNumbers(16));
        expenseBill.setType(elderlyInfo.getInStatusType() == 2 ? 3 : 1);
        expenseBill.setTenantId(createReqVO.getTenantId());
        expenseOrderMapper.insert(expenseBill);

        LocalDate localDate = createReqVO.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        int monthDays = localDate.lengthOfMonth();
        //计算月度费用
        BigDecimal amount = BigDecimal.ZERO;  //账单实际金额

        for (ExpenseItemDO item : monthlyExpenses) {
            item.setIsMonthlyExpense(BooleanEnum.TRUE.getValue());
            item.setItemCategoryName(categoryMap.getOrDefault(item.getItemCategoryId(),new SysChargeCategoryDO()).getName());
            item.setExpenseId(expense.getId());
            item.setTenantId(createReqVO.getTenantId());
            item.setChangeStartDate(date);
            expenseItemMapper.insert(item);


            //生成子账单
            ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
            orderItemDO.setExpenseOrderId(expenseBill.getId());
            orderItemDO.setSourceExpenseItemId(item.getId());
            orderItemDO.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
            orderItemDO.setCount(item.getCount());
            orderItemDO.setItemName(item.getItemName());


            //判断是否是月初一号入住的，那就按照一整月计算，不要按照天数算
            if(item.getIsDayCalculate() == 1){
                orderItemDO.setPrice(item.getAmount());
                orderItemDO.setActualPrice(item.getActualAmount());
                orderItemDO.setTotalAmount(item.getTotalAmount().multiply(new BigDecimal(daysUntilMonthEnd)));
                orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
                orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
                amount = amount.add(orderItemDO.getTotalAmount());
            }else {
                if (localDate.getDayOfMonth() == 1) {
                    amount = amount.add(item.getActualAmount());
                    orderItemDO.setPrice(item.getAmount());
                    orderItemDO.setActualPrice(item.getActualAmount());
                    orderItemDO.setTotalAmount(item.getTotalAmount());
                    orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
                    orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
                } else {
                    BigDecimal actualAmount = item.getActualAmount();
                    BigDecimal dayPrice = actualAmount.divide(BigDecimal.valueOf(monthDays), 8, RoundingMode.DOWN);
                    BigDecimal actualPrice = dayPrice.multiply(BigDecimal.valueOf(daysUntilMonthEnd)).setScale(8, RoundingMode.DOWN);
                    amount = amount.add(actualPrice.setScale(2, RoundingMode.HALF_UP));

                    orderItemDO.setPrice(item.getAmount());
                    orderItemDO.setActualPrice(item.getActualAmount());
                    orderItemDO.setTotalAmount(actualPrice);
                    orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
                    orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
                }
            }
            orderItemDO.setCreatedTime(new Date());
            orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            orderItemDO.setType(item.getType());
            orderItemDO.setTenantId(createReqVO.getTenantId());
            orderItemDO.setItemCategoryName(item.getItemCategoryName());
            orderItemDO.setStartDate(localDate);
            orderItemDO.setEndDate(localDate.with(TemporalAdjusters.lastDayOfMonth()));
            expenseOrderItemMapper.insert(orderItemDO);

        }

        //计算其他费用
        for (ExpenseItemDO item : oneTimeExpenses) {
            item.setExpenseId(expense.getId());
            item.setItemCategoryName(categoryMap.getOrDefault(item.getItemCategoryId(),new SysChargeCategoryDO()).getName());
            if (item.getIsDeposit() != null && item.getIsDeposit() != 1) {
                item.setIsOneTimeFee(BooleanEnum.TRUE.getValue());
            }
            expenseItemMapper.insert(item);
            //生成子账单
            ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
            orderItemDO.setSourceExpenseItemId(item.getId());
            orderItemDO.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
            orderItemDO.setCount(item.getCount());
            orderItemDO.setItemName(item.getItemName());
            orderItemDO.setExpenseOrderId(expenseBill.getId());
            orderItemDO.setPrice(item.getAmount());
            orderItemDO.setActualPrice(item.getActualAmount());
            orderItemDO.setTotalAmount(orderItemDO.getActualPrice().multiply(BigDecimal.valueOf(orderItemDO.getCount())).setScale(8, RoundingMode.DOWN));
            orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
            orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
            orderItemDO.setCreatedTime(new Date());
            orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            orderItemDO.setType(item.getType());
            orderItemDO.setItemCategoryName(item.getItemCategoryName());
            orderItemDO.setTenantId(createReqVO.getTenantId());
            expenseOrderItemMapper.insert(orderItemDO);

            amount = amount.add(orderItemDO.getTotalAmount().setScale(2, RoundingMode.DOWN));
        }

        //计算阶段性费用
        for (ExpenseItemDO stageExpenseItem : stageExpenses) {
            stageExpenseItem.setExpenseId(expense.getId());
            stageExpenseItem.setTenantId(createReqVO.getTenantId());
            stageExpenseItem.setItemCategoryName(categoryMap.getOrDefault(stageExpenseItem.getItemCategoryId(),new SysChargeCategoryDO()).getName());
            expenseItemMapper.insert(stageExpenseItem);

            if (stageExpenseItem.getIsHirePurchase().equals(BooleanEnum.TRUE.getValue())) {
                Integer hirePurchaseNumber = stageExpenseItem.getHirePurchaseNumber(); //分期期数
                for (int i = 0; i < hirePurchaseNumber; i++) {
                    YearMonth now = YearMonth.now();
                    YearMonth yearMonth = now.plusMonths(i);
                    String hirePurchaseTime = yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));

                    //生成分期费用
                    if (i == 0) {
                        //第一期生成账单
                        DailyExpensesDO dailyExpenses = new DailyExpensesDO();
                        dailyExpenses.setType(5); // 5：分期
                        dailyExpenses.setExpenseOrderNumber(expenseBill.getBillOrderNumber());
                        dailyExpenses.setElderId(createReqVO.getElderId());
                        dailyExpenses.setAttributionBillTime(hirePurchaseTime);
                        dailyExpenses.setItemId(stageExpenseItem.getId());
                        dailyExpenses.setItemCategory(stageExpenseItem.getItemCategoryName());
                        dailyExpenses.setItemName(stageExpenseItem.getItemName());
                        dailyExpenses.setPrice(stageExpenseItem.getHirePurchaseAmount());
                        dailyExpenses.setAmount(stageExpenseItem.getHirePurchaseAmount());
                        dailyExpenses.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));
                        dailyExpenses.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));
                        dailyExpenses.setRemarks("费用分期付款：" + dailyExpenses.getItemName() + "，分期金额：" + stageExpenseItem.getTotalAmount()
                                + "元，分" + stageExpenseItem.getHirePurchaseNumber() + "期还款，当前还款第" + (i + 1) + "期，还款金额为：" + dailyExpenses.getAmount() + "元");
                        dailyExpenses.setCount(1);
                        dailyExpenses.setCreatedTime(new Date());
                        dailyExpenses.setAccountingTime(new Date());
                        dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
                        dailyExpenses.setTenantId(createReqVO.getTenantId());
                        dailyExpensesMapper.insert(dailyExpenses);

                        //生成账单
                        ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
                        orderItemDO.setSourceExpenseItemId(dailyExpenses.getId());
                        orderItemDO.setExpenseSource(BusinessConstants.DAILY_EXPENSES);
                        orderItemDO.setCount(stageExpenseItem.getCount());
                        orderItemDO.setItemName(stageExpenseItem.getItemName());
                        orderItemDO.setExpenseOrderId(expenseBill.getId());
                        orderItemDO.setPrice(stageExpenseItem.getAmount());
                        orderItemDO.setActualPrice(stageExpenseItem.getAmount());
                        orderItemDO.setTotalAmount(stageExpenseItem.getHirePurchaseAmount());  //分期金额
                        orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
                        orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
                        orderItemDO.setCreatedTime(new Date());
                        orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
                        orderItemDO.setType(stageExpenseItem.getType());
                        orderItemDO.setItemCategoryName(stageExpenseItem.getItemCategoryName());
                        orderItemDO.setTenantId(createReqVO.getTenantId());
                        expenseOrderItemMapper.insert(orderItemDO);

                        amount = amount.add(orderItemDO.getTotalAmount().setScale(2, RoundingMode.DOWN));

                    } else {

                        DailyExpensesDO dailyExpenses = new DailyExpensesDO();
                        dailyExpenses.setType(5); // 5：分期
                        dailyExpenses.setElderId(createReqVO.getElderId());
                        dailyExpenses.setAttributionBillTime(hirePurchaseTime);
                        dailyExpenses.setItemId(stageExpenseItem.getId());
                        dailyExpenses.setItemCategory(stageExpenseItem.getItemCategoryName());
                        dailyExpenses.setItemName(stageExpenseItem.getItemName());
                        dailyExpenses.setPrice(stageExpenseItem.getHirePurchaseAmount());
                        dailyExpenses.setAmount(stageExpenseItem.getHirePurchaseAmount());
                        dailyExpenses.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));
                        dailyExpenses.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));
                        dailyExpenses.setRemarks("费用分期付款：" + dailyExpenses.getItemName() + "，分期金额：" + stageExpenseItem.getTotalAmount()
                                + "元，分" + stageExpenseItem.getHirePurchaseNumber() + "期还款，当前还款第" + (i + 1) + "期，还款金额为：" + dailyExpenses.getAmount() + "元");
                        dailyExpenses.setCount(1);
                        Date from = Date.from(yearMonth.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
                        dailyExpenses.setCreatedTime(from);
                        dailyExpenses.setAccountingTime(new Date());
                        dailyExpenses.setIsGenerateBill(BooleanEnum.FALSE.getValue());
                        dailyExpenses.setTenantId(createReqVO.getTenantId());
                        dailyExpensesMapper.insert(dailyExpenses);
                    }
                }
            } else {
                //赠送的
                if (new Date().getTime() > stageExpenseItem.getFreeStartTime().getTime()) {
                    //生成收费项
                    ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
                    orderItemDO.setSourceExpenseItemId(stageExpenseItem.getId());
                    orderItemDO.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
                    orderItemDO.setCount(stageExpenseItem.getCount());
                    orderItemDO.setItemName(stageExpenseItem.getItemName());
                    orderItemDO.setExpenseOrderId(expenseBill.getId());
                    orderItemDO.setPrice(stageExpenseItem.getAmount());
                    orderItemDO.setActualPrice(BigDecimal.ZERO);
                    orderItemDO.setTotalAmount(BigDecimal.ZERO);
                    orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
                    orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
                    orderItemDO.setCreatedTime(new Date());
                    orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
                    orderItemDO.setType(stageExpenseItem.getType());
                    orderItemDO.setItemCategoryName(stageExpenseItem.getItemCategoryName());
                    orderItemDO.setTenantId(createReqVO.getTenantId());
                    expenseOrderItemMapper.insert(orderItemDO);
                }
            }
        }
        BigDecimal reservationDeposit = handleReservation(elderlyInfo.getElderName(), expenseBill.getId());
        expenseBill.setActualAmount(amount.add(reservationDeposit));
        expenseOrderMapper.updateById(expenseBill);
        //生成押金记录
        DepositDO deposit = depositMapper.selectOne(new LambdaQueryWrapper<DepositDO>().eq(DepositDO::getElderId, elderId));
        if (deposit == null) {
            deposit = new DepositDO();
            deposit.setElderId(elderId);
            deposit.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            deposit.setCreatedTime(new Date());
            deposit.setAmount(BigDecimal.ZERO);
            deposit.setTenantId(createReqVO.getTenantId());
            depositMapper.insert(deposit);
        }
        //生成余额
        balanceService.createBalance(elderId);
        return expenseBill.getId();
    }

    @Override
    public ExpenseRespVO getExpense(Long elderId, Long contractId) {
        List<ExpenseDO> expenses = expenseMapper.selectList(new LambdaQueryWrapperX<ExpenseDO>()
                .eq(ExpenseDO::getElderId, elderId)
//                .eqIfPresent(ExpenseDO::getContractId, contractId)
                .orderByDesc(ExpenseDO::getCreatedTime));
        if (CollectionUtil.isNotEmpty(expenses)) {
            Optional<ExpenseDO> optional = expenses.stream().findFirst();
            if (optional.isPresent()) {
                ExpenseDO expense = optional.get();
                List<ExpenseItemDO> expenseItems = expenseItemMapper.selectList(new LambdaQueryWrapperX<ExpenseItemDO>()
                        .eq(ExpenseItemDO::getExpenseId, expense.getId()));

                ElderlyInfoDO elderlyInfo = elderlyInfoMapper.selectById(elderId);

                ExpenseRespVO respVO = new ExpenseRespVO();
                respVO.setExpenseItems(expenseItems);
                respVO.setElderId(elderlyInfo.getId());
                respVO.setElderName(elderlyInfo.getElderName());
                respVO.setIsPrivateRoom(elderlyInfo.getIsPrivateRoom());
                respVO.setSpecialCareNotes(elderlyInfo.getSpecialCareNotes());
                respVO.setBedName(buildService.getFullBedName(elderId));
                respVO.setBedId(elderlyInfo.getBedId());
                respVO.setNurseLevelId(elderlyInfo.getNurseLevelId());
                respVO.setTenantId(elderlyInfo.getTenantId());
                ElderlyContractDO elderlyContract = elderlyContractMapper.selectOne(new LambdaQueryWrapperX<ElderlyContractDO>()
                        .eq(ElderlyContractDO::getElderId, elderId)
                        .eq(ElderlyContractDO::getId, contractId));

                if (elderlyContract != null) {
                    List<ElderlyContractDetailDO> elderlyContractDetail = elderlyContractDetailMapper.selectList(new LambdaQueryWrapperX<ElderlyContractDetailDO>()
                            .eq(ElderlyContractDetailDO::getContractId, elderlyContract.getId()));
                    elderlyContract.setDetails(elderlyContractDetail);
                }
                respVO.setContract(elderlyContract);
                return respVO;
            }
        }
        return null;
    }

    @Override
    @Transactional
    public void renewContract(ExpenseSaveReqVO createReqVO) {
        checkElderOrderExist(createReqVO);
        if(createReqVO.getOldContractId() != null){
            if(elderlyContractMapper.selectById(createReqVO.getOldContractId()).getIsRenew() == 1){
                throw exceptionCustomMsg(ErrorCodeConstants.COMMON_ERROR,"已续约不能重复续约");
            }
            elderlyContractMapper.updateById(new ElderlyContractDO().setId(createReqVO.getOldContractId()).setIsRenew(1));
        }
        // 将最新的费用记录的结束日期更新为续约日期的前一天
        ExpenseDO expenseDO = expenseMapper.selectList(new LambdaQueryWrapperX<ExpenseDO>()
                .eq(ExpenseDO::getElderId, createReqVO.getElderId())
                .orderByDesc(ExpenseDO::getCreatedTime)).get(0);
        List<ExpenseItemDO> expenseItemDOS = expenseItemMapper.selectList(new LambdaQueryWrapperX<ExpenseItemDO>().eq(ExpenseItemDO::getExpenseId, expenseDO.getId()));
        LocalDate changeEndDate = createReqVO.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().minusDays(1);
        for (ExpenseItemDO expenseItemDO : expenseItemDOS) {
            expenseItemDO.setChangeEndDate(changeEndDate);
            expenseItemMapper.updateById(expenseItemDO);
        }
        List<ExpenseItemDO> monthlyExpenses = createReqVO.getMonthlyExpenses();
        List<ExpenseItemDO> oneTimeExpenses = createReqVO.getOneTimeExpenses();
        List<ExpenseItemDO> stageExpenses = createReqVO.getStageExpenses();

        //创建月度账单费用
        ExpenseDO expense = new ExpenseDO();
        BeanUtils.copyProperties(createReqVO, expense);
        expense.setCreatedTime(new Date());
        expense.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        expense.setTenantId(TenantContextHolder.getTenantId());
        expenseMapper.insert(expense);

        updateElderlyInfo(createReqVO, expense);

        LocalDate date = createReqVO.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate monthEnd = date.with(TemporalAdjusters.lastDayOfMonth());
        int monthDays = date.lengthOfMonth(); //当月天数
        long daysUntilMonthEnd = ChronoUnit.DAYS.between(date, monthEnd) + 1; //天数
        String billingMonth = date.format(DateTimeFormatter.ofPattern("yyyy-MM"));
        
        // 根据长者的入住类型确定账单类型
        // inStatusType: 1=入住(长住), 2=试住, 3=短住
        // type: 1=入院账单, 2=月度账单, 3=试住账单
        int billType = (createReqVO.getInStatusType() != null && createReqVO.getInStatusType() == 2) ? 3 : 2;
        
        // 查询对应类型的账单（试住账单或入院账单）
        ExpenseOrderDO expenseOrderDO = expenseOrderMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getBillingMonth, billingMonth)
                .eq(ExpenseOrderDO::getElderId, createReqVO.getElderId())
                .eq(ExpenseOrderDO::getTenantId, createReqVO.getTenantId())
                .eq(ExpenseOrderDO::getType, billType)
                .eq(ExpenseOrderDO::getPayStatus,BooleanEnum.FALSE.getValue())); // 根据长者类型查询对应类型的账单

        boolean isNewBill = (expenseOrderDO == null);
        if (isNewBill) {
            expenseOrderDO = createNewExpenseOrder(createReqVO, date);
        }

        BigDecimal totalAmount = processMonthlyExpenses(createReqVO, expense, monthlyExpenses, date, monthEnd, monthDays, daysUntilMonthEnd, expenseOrderDO, isNewBill);
        totalAmount = totalAmount.add(processOneTimeExpenses(createReqVO, expense, oneTimeExpenses, expenseOrderDO));
        totalAmount = totalAmount.add(processStageExpenses(createReqVO, expense, stageExpenses, expenseOrderDO));
        totalAmount = totalAmount.add(processRenewContractSupplementExpenses(createReqVO, expenseOrderDO, date, monthEnd, isNewBill));

        if (isNewBill) {
            expenseOrderDO.setActualAmount(totalAmount);
        } else {
            //合并账单
            expenseOrderDO.setActualAmount(expenseOrderDO.getActualAmount().add(totalAmount));
        }
        expenseOrderMapper.updateById(expenseOrderDO);

        //合同信息
        Long contractId = saveContractInfo(createReqVO);
        expense.setContractId(contractId);
        expenseMapper.updateById(expense);
        addCheckInApply(createReqVO);
    }

    @Override
    @Transactional
    public void appendFixedExpense(ElderlyFixedExpenseAppendReqVO reqVO) {
        Long tenantId = reqVO.getTenantId() == null ? TenantContextHolder.getTenantId() : reqVO.getTenantId();

        ExpenseDO expense = expenseMapper.selectOne(new LambdaQueryWrapperX<ExpenseDO>()
                .eq(ExpenseDO::getElderId, reqVO.getElderId())
                .eq(tenantId != null, ExpenseDO::getTenantId, tenantId)
                .orderByDesc(ExpenseDO::getCreatedTime)
                .last("LIMIT 1"));

        if (expense == null) {
            expense = new ExpenseDO();
            expense.setElderId(reqVO.getElderId());
            expense.setTenantId(tenantId);
            expense.setRemark("手工追加固定费项创建");
            expense.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            expense.setCreatedTime(new Date());
            expense.setTotalAmount(BigDecimal.ZERO);
            expenseMapper.insert(expense);
        }

        int count = Optional.ofNullable(reqVO.getCount()).orElse(1);
        if (count <= 0) {
            throw exceptionCustomMsg(ErrorCodeConstants.COMMON_ERROR, "数量必须大于0");
        }

        LocalDate startDate = reqVO.getStartDate();
        LocalDate endDate = reqVO.getEndDate() == null ? startDate : reqVO.getEndDate();
        if (endDate.isBefore(startDate)) {
            throw exceptionCustomMsg(ErrorCodeConstants.COMMON_ERROR, "结束时间不能早于开始时间");
        }

        BigDecimal actualAmount = reqVO.getActualAmount() == null ? reqVO.getAmount() : reqVO.getActualAmount();
        BigDecimal totalAmount = actualAmount.multiply(BigDecimal.valueOf(count)).setScale(2, RoundingMode.HALF_UP);

        ExpenseItemDO item = new ExpenseItemDO();
        item.setExpenseId(expense.getId());
        item.setItemId(reqVO.getItemId());
        item.setItemCategoryName(reqVO.getItemCategoryName());
        item.setItemName(reqVO.getItemName());
        item.setAmount(reqVO.getAmount());
        item.setActualAmount(actualAmount);
        item.setCount(count);
        item.setTotalAmount(totalAmount);
        item.setType(reqVO.getType());
        item.setIsMonthlyExpense(BooleanEnum.TRUE.getValue());
        item.setIsOneTimeFee(BooleanEnum.FALSE.getValue());
        item.setTenantId(tenantId);
        item.setCreateTime(new Date());

        item.setChangeStartDate(startDate);
        item.setChangeEndDate(endDate);

        String targetBillingMonth = YearMonth.from(startDate).format(DateTimeFormatter.ofPattern("yyyy-MM"));

        expenseItemMapper.insert(item);

        // 追加费项后，立即触发目标月份账单补差
        reconcileCurrentMonthBillAfterAppend(reqVO.getElderId(), tenantId, item, targetBillingMonth, startDate, endDate);
    }

    /**
     * 追加固定费项后，对当月账单进行补差（新增一条账单明细）
     */
    private void reconcileCurrentMonthBillAfterAppend(Long elderId, Long tenantId, ExpenseItemDO item,
                                                      String targetBillingMonth, LocalDate startDate, LocalDate endDate) {
        List<ExpenseOrderDO> currentOrderList = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getElderId, elderId)
                .ge(ExpenseOrderDO::getBillingMonth, targetBillingMonth)
                .in(ExpenseOrderDO::getType, 2, 3)
                .eq(tenantId != null, ExpenseOrderDO::getTenantId, tenantId)
                .orderByDesc(ExpenseOrderDO::getCreatedTime)
                .last("LIMIT 1"));

        if (currentOrderList == null) {
            return;
        }
        for (ExpenseOrderDO currentOrder : currentOrderList) {
            if (Boolean.TRUE.equals(currentOrder.getConfirmStatus()) || Boolean.TRUE.equals(currentOrder.getIsLock())) {
                throw exceptionCustomMsg(ErrorCodeConstants.COMMON_ERROR, "当月账单已确认或已锁定，无法自动补差");
            }

            YearMonth billingYm = YearMonth.parse(targetBillingMonth, DateTimeFormatter.ofPattern("yyyy-MM"));
            LocalDate billStart = billingYm.atDay(1);
            LocalDate billEnd = billingYm.atEndOfMonth();

            LocalDate actualStart = startDate.isBefore(billStart) ? billStart : startDate;
            LocalDate actualEnd = endDate.isAfter(billEnd) ? billEnd : endDate;
            if (actualEnd.isBefore(actualStart)) {
                return;
            }

            long overlapDays = ChronoUnit.DAYS.between(actualStart, actualEnd) + 1;
            int monthDays = billingYm.lengthOfMonth();
            BigDecimal dayPrice = item.getActualAmount().divide(BigDecimal.valueOf(monthDays), 8, RoundingMode.DOWN);
            BigDecimal billDeltaAmount = item.getActualAmount();
            if(currentOrder.getBillingMonth().equals(targetBillingMonth)){
                billDeltaAmount = dayPrice.multiply(BigDecimal.valueOf(overlapDays)).setScale(2, RoundingMode.HALF_UP);
            }
            if (billDeltaAmount.compareTo(BigDecimal.ZERO) == 0) {
                return;
            }

            ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
            orderItem.setExpenseOrderId(currentOrder.getId());
            orderItem.setSourceExpenseItemId(item.getId());
            orderItem.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
            orderItem.setCount((int) overlapDays);
            orderItem.setItemName(item.getItemName());
            orderItem.setItemCategoryName(item.getItemCategoryName());
            orderItem.setPrice(item.getAmount());
            orderItem.setActualPrice(dayPrice);
            orderItem.setTotalAmount(billDeltaAmount);
            orderItem.setRoundAmount(billDeltaAmount.setScale(0, RoundingMode.HALF_UP));
            orderItem.setRoundTwoDecimalAmount(billDeltaAmount.setScale(2, RoundingMode.HALF_UP));
            orderItem.setCreatedTime(new Date());
            orderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            orderItem.setType(item.getType());
            orderItem.setTenantId(tenantId);
            orderItem.setStartDate(actualStart);
            orderItem.setEndDate(actualEnd);
            orderItem.setDescription("固定费项补差：" + actualStart + "至" + actualEnd + "，共" + overlapDays + "天，" + item.getItemName());
            expenseOrderItemMapper.insert(orderItem);

            BigDecimal billAmount = currentOrder.getActualAmount() == null ? BigDecimal.ZERO : currentOrder.getActualAmount();
            currentOrder.setActualAmount(billAmount.add(billDeltaAmount));
            currentOrder.setPayStatus(BooleanEnum.FALSE.getValue());
            currentOrder.setPayType(null);
            expenseOrderMapper.updateById(currentOrder);
        }
    }

    /**
     * 更新长者床位信息
     */
    private void updateElderlyInfo(ExpenseSaveReqVO createReqVO, ExpenseDO expense) {
        Long elderId = createReqVO.getElderId();
        ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectById(elderId);
        if (createReqVO.getInStatusType() != null) {
            elderlyInfoDO.setInStatusType(createReqVO.getInStatusType());
        }
        Long bedId = elderlyInfoDO.getBedId();
        if (bedId != null && !bedId.equals(createReqVO.getBedId())) {
            BuildBedDO oldBed = buildBedMapper.selectById(bedId);
            BuildBedDO newBed = buildBedMapper.selectById(createReqVO.getBedId());

            if (oldBed != null && newBed != null) {
                elderlyInfoDO.setBedId(newBed.getId());
                elderlyInfoDO.setBedName(newBed.getBedName());
                elderlyInfoDO.setRoomId(newBed.getRoomId());
                elderlyInfoDO.setFloorId(newBed.getFloorId());
                elderlyInfoDO.setBuildId(newBed.getBuildId());
                elderlyInfoDO.setNurseLevelId(createReqVO.getNurseLevelId());
                elderlyInfoDO.setCheckInTime(createReqVO.getCheckInTime());
                elderlyInfoDO.setInStatus(1);
                newBed.setStatus(1);
                oldBed.setStatus(0);
                buildBedMapper.updateById(newBed);
                buildBedMapper.updateById(oldBed);
            }
        }else {
            BuildBedDO newBed = buildBedMapper.selectById(createReqVO.getBedId());
            elderlyInfoDO.setBedId(newBed.getId());
            elderlyInfoDO.setBedName(newBed.getBedName());
            elderlyInfoDO.setRoomId(newBed.getRoomId());
            elderlyInfoDO.setFloorId(newBed.getFloorId());
            elderlyInfoDO.setBuildId(newBed.getBuildId());
            elderlyInfoDO.setNurseLevelId(createReqVO.getNurseLevelId());
            elderlyInfoDO.setCheckInTime(createReqVO.getCheckInTime());
            elderlyInfoDO.setInStatus(1);
            newBed.setStatus(1);
            buildBedMapper.updateById(newBed);
        }
        elderlyInfoDO.setInStatusType(createReqVO.getInStatusType());
        elderlyInfoMapper.updateById(elderlyInfoDO);

        //更改入住信息
        ElderlyCheckInRecordDO elderlyCheckInRecordDO = elderlyCheckInRecordMapper.selectOne(new LambdaQueryWrapperX<ElderlyCheckInRecordDO>()
                .eq(ElderlyCheckInRecordDO::getElderId, elderId)
                .eq(ElderlyCheckInRecordDO::getCurrentFlag,0));

        if (elderlyCheckInRecordDO != null){
            elderlyCheckInRecordDO.setStatus(2);
            elderlyCheckInRecordDO.setCheckInTime(createReqVO.getCheckInTime());
            elderlyCheckInRecordMapper.updateById(elderlyCheckInRecordDO);
        }
    }

    /**
     * 创建新的费用订单
     */
    private ExpenseOrderDO createNewExpenseOrder(ExpenseSaveReqVO createReqVO, LocalDate date) {
        // 根据长者的入住类型确定账单类型
        // inStatusType: 1=入住(长住), 2=试住, 3=短住
        // type: 1=入院账单, 2=月度账单, 3=试住账单
        int billType = (createReqVO.getInStatusType() != null && createReqVO.getInStatusType() == 2) ? 3 : 2;
        
        ExpenseOrderDO expenseOrderDO = new ExpenseOrderDO();
        expenseOrderDO.setBillingMonth(date.format(DateTimeFormatter.ofPattern("yyyy-MM")));
        expenseOrderDO.setCreatedTime(new Date());
        expenseOrderDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        expenseOrderDO.setElderId(createReqVO.getElderId());
        expenseOrderDO.setBillOrderNumber("E" + RandomUtil.randomNumbers(16));
        expenseOrderDO.setType(billType); // 根据长者入住类型设置账单类型
        expenseOrderDO.setTenantId(createReqVO.getTenantId());
        expenseOrderMapper.insert(expenseOrderDO);
        return expenseOrderDO;
    }

    /**
     * 处理月度费用
     */
    private BigDecimal processMonthlyExpenses(ExpenseSaveReqVO createReqVO, ExpenseDO expense, List<ExpenseItemDO> monthlyExpenses,
                                              LocalDate date, LocalDate monthEnd, int monthDays, long daysUntilMonthEnd,
                                              ExpenseOrderDO expenseOrderDO, boolean isNewBill) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (ExpenseItemDO item : monthlyExpenses) {
            item.setIsMonthlyExpense(BooleanEnum.TRUE.getValue());
            item.setExpenseId(expense.getId());
            item.setTenantId(createReqVO.getTenantId());
            item.setChangeStartDate(date);
            expenseItemMapper.insert(item);

            BigDecimal actualAmount = item.getActualAmount();
            BigDecimal dayPrice = actualAmount.divide(BigDecimal.valueOf(monthDays), 8, RoundingMode.DOWN);
            BigDecimal actualPrice = dayPrice.multiply(BigDecimal.valueOf(daysUntilMonthEnd)).setScale(8, RoundingMode.DOWN);
            totalAmount = totalAmount.add(actualPrice.setScale(2, RoundingMode.HALF_UP));

            //生成子账单
            ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
            orderItemDO.setExpenseOrderId(expenseOrderDO.getId());
            orderItemDO.setSourceExpenseItemId(item.getId());
            orderItemDO.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
            orderItemDO.setCount(item.getCount());
            orderItemDO.setItemName(item.getItemName());
            orderItemDO.setPrice(item.getAmount());
            orderItemDO.setActualPrice(item.getActualAmount());
            orderItemDO.setTotalAmount(actualPrice);
            orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
            orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
            orderItemDO.setCreatedTime(new Date());
            orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            orderItemDO.setType(item.getType());
            orderItemDO.setTenantId(createReqVO.getTenantId());
            orderItemDO.setItemCategoryName(item.getItemCategoryName());
            orderItemDO.setStartDate(date);
            orderItemDO.setEndDate(monthEnd);
            orderItemDO.setDescription(LocalDateTimeUtil.format(date, DatePattern.NORM_DATE_PATTERN) + "至" + LocalDateTimeUtil.format(monthEnd, DatePattern.NORM_DATE_PATTERN) + "的" + item.getItemName());
            expenseOrderItemMapper.insert(orderItemDO);
        }
        return totalAmount;
    }

    /**
     * 处理一次性费用
     */
    private BigDecimal processOneTimeExpenses(ExpenseSaveReqVO createReqVO, ExpenseDO expense, List<ExpenseItemDO> oneTimeExpenses, ExpenseOrderDO expenseOrderDO) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (ExpenseItemDO item : oneTimeExpenses) {
            item.setExpenseId(expense.getId());
            if (item.getIsDeposit() != 1) {
                item.setIsOneTimeFee(BooleanEnum.TRUE.getValue());
            }
            expenseItemMapper.insert(item);
            //生成子账单
            ExpenseOrderItemDO orderItemDO = createOrderItemFromExpenseItem(item, createReqVO, expenseOrderDO);
            orderItemDO.setTotalAmount(orderItemDO.getActualPrice().multiply(BigDecimal.valueOf(orderItemDO.getCount())).setScale(8, RoundingMode.DOWN));
            orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
            orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
            expenseOrderItemMapper.insert(orderItemDO);

            totalAmount = totalAmount.add(orderItemDO.getTotalAmount().setScale(2, RoundingMode.DOWN));
        }
        return totalAmount;
    }

    /**
     * 处理阶段性费用
     */
    private BigDecimal processStageExpenses(ExpenseSaveReqVO createReqVO, ExpenseDO expense, List<ExpenseItemDO> stageExpenses, ExpenseOrderDO expenseOrderDO) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (ExpenseItemDO stageExpenseItem : stageExpenses) {
            stageExpenseItem.setExpenseId(expense.getId());
            stageExpenseItem.setTenantId(createReqVO.getTenantId());
            expenseItemMapper.insert(stageExpenseItem);

            if (stageExpenseItem.getIsHirePurchase().equals(BooleanEnum.TRUE.getValue())) {
                totalAmount = totalAmount.add(processHirePurchaseExpense(createReqVO, stageExpenseItem, expenseOrderDO));
            } else {
                //赠送的
                if (new Date().getTime() > stageExpenseItem.getFreeStartTime().getTime()) {
                    //生成收费项
                    ExpenseOrderItemDO orderItemDO = createOrderItemFromExpenseItem(stageExpenseItem, createReqVO, expenseOrderDO);
                    orderItemDO.setActualPrice(BigDecimal.ZERO);
                    orderItemDO.setTotalAmount(BigDecimal.ZERO);
                    orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
                    orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
                    expenseOrderItemMapper.insert(orderItemDO);
                }
            }
        }
        return totalAmount;
    }

    /**
     * 处理分期费用
     */
    private BigDecimal processHirePurchaseExpense(ExpenseSaveReqVO createReqVO, ExpenseItemDO stageExpenseItem, ExpenseOrderDO expenseOrderDO) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        Integer hirePurchaseNumber = stageExpenseItem.getHirePurchaseNumber(); //分期期数
        for (int i = 0; i < hirePurchaseNumber; i++) {
            YearMonth now = YearMonth.now();
            YearMonth yearMonth = now.plusMonths(i);
            String hirePurchaseTime = yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));

            //生成分期费用
            if (i == 0) {
                //第一期生成账单
                DailyExpensesDO dailyExpenses = new DailyExpensesDO();
                dailyExpenses.setType(5); // 5：分期
                dailyExpenses.setExpenseOrderNumber(expenseOrderDO.getBillOrderNumber());
                dailyExpenses.setElderId(createReqVO.getElderId());
                dailyExpenses.setAttributionBillTime(hirePurchaseTime);
                dailyExpenses.setItemId(stageExpenseItem.getId());
                dailyExpenses.setItemCategory(stageExpenseItem.getItemCategoryName());
                dailyExpenses.setItemName(stageExpenseItem.getItemName());
                dailyExpenses.setPrice(stageExpenseItem.getHirePurchaseAmount());
                dailyExpenses.setAmount(stageExpenseItem.getHirePurchaseAmount());
                dailyExpenses.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));
                dailyExpenses.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));
                dailyExpenses.setRemarks("费用分期付款：" + dailyExpenses.getItemName() + "，分期金额：" + stageExpenseItem.getTotalAmount()
                        + "元，分" + stageExpenseItem.getHirePurchaseNumber() + "期还款，当前还款第" + (i + 1) + "期，还款金额为：" + dailyExpenses.getAmount() + "元");
                dailyExpenses.setCount(1);
                dailyExpenses.setCreatedTime(new Date());
                dailyExpenses.setAccountingTime(new Date());
                dailyExpenses.setIsGenerateBill(BooleanEnum.TRUE.getValue());
                dailyExpenses.setTenantId(createReqVO.getTenantId());
                dailyExpensesMapper.insert(dailyExpenses);

                //生成账单
                ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
                orderItemDO.setSourceExpenseItemId(dailyExpenses.getId());
                orderItemDO.setExpenseSource(BusinessConstants.DAILY_EXPENSES);
                orderItemDO.setCount(stageExpenseItem.getCount());
                orderItemDO.setItemName(stageExpenseItem.getItemName());
                orderItemDO.setExpenseOrderId(expenseOrderDO.getId());
                orderItemDO.setPrice(stageExpenseItem.getAmount());
                orderItemDO.setActualPrice(stageExpenseItem.getAmount());
                orderItemDO.setTotalAmount(stageExpenseItem.getHirePurchaseAmount());  //分期金额
                orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
                orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
                orderItemDO.setCreatedTime(new Date());
                orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
                orderItemDO.setType(stageExpenseItem.getType());
                orderItemDO.setItemCategoryName(stageExpenseItem.getItemCategoryName());
                orderItemDO.setTenantId(createReqVO.getTenantId());
                expenseOrderItemMapper.insert(orderItemDO);

                totalAmount = totalAmount.add(orderItemDO.getTotalAmount().setScale(2, RoundingMode.DOWN));

            } else {

                DailyExpensesDO dailyExpenses = new DailyExpensesDO();
                dailyExpenses.setType(5); // 5：分期
                dailyExpenses.setElderId(createReqVO.getElderId());
                dailyExpenses.setAttributionBillTime(hirePurchaseTime);
                dailyExpenses.setItemId(stageExpenseItem.getId());
                dailyExpenses.setItemCategory(stageExpenseItem.getItemCategoryName());
                dailyExpenses.setItemName(stageExpenseItem.getItemName());
                dailyExpenses.setPrice(stageExpenseItem.getHirePurchaseAmount());
                dailyExpenses.setAmount(stageExpenseItem.getHirePurchaseAmount());
                dailyExpenses.setRoundAmount(dailyExpenses.getAmount().setScale(0, RoundingMode.HALF_UP));
                dailyExpenses.setRoundTwoDecimalAmount(dailyExpenses.getAmount().setScale(2, RoundingMode.HALF_UP));
                dailyExpenses.setRemarks("费用分期付款：" + dailyExpenses.getItemName() + "，分期金额：" + stageExpenseItem.getTotalAmount()
                        + "元，分" + stageExpenseItem.getHirePurchaseNumber() + "期还款，当前还款第" + (i + 1) + "期，还款金额为：" + dailyExpenses.getAmount() + "元");
                dailyExpenses.setCount(1);
                Date from = Date.from(yearMonth.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
                dailyExpenses.setCreatedTime(from);
                dailyExpenses.setAccountingTime(new Date());
                dailyExpenses.setIsGenerateBill(BooleanEnum.FALSE.getValue());
                dailyExpenses.setTenantId(createReqVO.getTenantId());
                dailyExpensesMapper.insert(dailyExpenses);
            }
        }
        return totalAmount;
    }

    /**
     * 续约时补充未生成账单的长护险、消费券、日常费用
     */
    private BigDecimal processRenewContractSupplementExpenses(ExpenseSaveReqVO createReqVO, ExpenseOrderDO expenseOrderDO,
                                                              LocalDate actualStart, LocalDate actualEnd, boolean isNewBill) {
        if (!isNewBill) {
            return BigDecimal.ZERO;
        }
        String billingMonth = actualStart.format(DateTimeFormatter.ofPattern("yyyy-MM"));
        YearMonth yearMonth = YearMonth.from(actualStart);

        BigDecimal totalAmount = BigDecimal.ZERO;
        totalAmount = totalAmount.add(processRenewDailyExpenses(createReqVO, expenseOrderDO, billingMonth, yearMonth));
        totalAmount = totalAmount.add(processRenewSubsidyExpenses(createReqVO, expenseOrderDO, billingMonth, actualStart, actualEnd));
        totalAmount = totalAmount.add(processRenewConsumerVoucherExpenses(createReqVO, expenseOrderDO, billingMonth, actualStart, actualEnd));
        return totalAmount;
    }

    private BigDecimal processRenewDailyExpenses(ExpenseSaveReqVO createReqVO, ExpenseOrderDO expenseOrderDO,
                                                 String billingMonth, YearMonth yearMonth) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        List<DailyExpensesDO> dailyExpensesList = dailyExpensesMapper.selectList(new LambdaQueryWrapperX<DailyExpensesDO>()
                .eq(DailyExpensesDO::getElderId, createReqVO.getElderId())
                .le(DailyExpensesDO::getAttributionBillTime, billingMonth)
                .eq(DailyExpensesDO::getStatus, BooleanEnum.FALSE.getValue())
                .eq(DailyExpensesDO::getIsGenerateBill, BooleanEnum.FALSE.getValue()));

        List<DailyExpensesDO> dailyExpensesUpdateList = new ArrayList<>();
        for (DailyExpensesDO item : dailyExpensesList) {
            ExpenseItemDO expenseItem = new ExpenseItemDO();
            expenseItem.setExpenseId(null);
            expenseItem.setItemId(item.getItemId());
            expenseItem.setItemCategoryName(item.getItemCategory());
            expenseItem.setItemName(item.getItemName());
            expenseItem.setAmount(item.getPrice());
            expenseItem.setActualAmount(item.getAmount());
            expenseItem.setCount(item.getCount());
            expenseItem.setTotalAmount(item.getAmount());
            expenseItem.setType(item.getType());
            expenseItem.setIsMonthlyExpense(BooleanEnum.FALSE.getValue());
            expenseItem.setIsOneTimeFee(BooleanEnum.FALSE.getValue());
            expenseItem.setTenantId(createReqVO.getTenantId());
            expenseItem.setCreateTime(new Date());
            expenseItemMapper.insert(expenseItem);

            ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
            orderItemDO.setExpenseOrderId(expenseOrderDO.getId());
            orderItemDO.setSourceExpenseItemId(expenseItem.getId());
            orderItemDO.setExpenseSource(BusinessConstants.DAILY_EXPENSES);
            orderItemDO.setCount(item.getCount());
            orderItemDO.setItemName(item.getItemName());
            orderItemDO.setItemCategoryName(item.getItemCategory());
            orderItemDO.setPrice(item.getPrice());
            orderItemDO.setActualPrice(item.getPrice());
            orderItemDO.setTotalAmount(item.getAmount());
            orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
            orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
            orderItemDO.setCreatedTime(new Date());
            orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            orderItemDO.setType(item.getType());
            orderItemDO.setTenantId(createReqVO.getTenantId());
            orderItemDO.setStartDate(yearMonth.atDay(1));
            orderItemDO.setEndDate(yearMonth.atEndOfMonth());
            orderItemDO.setDescription(item.getRemarks());
            expenseOrderItemMapper.insert(orderItemDO);

            item.setStatus(BooleanEnum.TRUE.getValue());
            item.setIsGenerateBill(BooleanEnum.TRUE.getValue());
            item.setExpenseOrderNumber(expenseOrderDO.getBillOrderNumber());
            dailyExpensesUpdateList.add(item);
            totalAmount = totalAmount.add(orderItemDO.getTotalAmount().setScale(2, RoundingMode.DOWN));
        }

        if (CollectionUtil.isNotEmpty(dailyExpensesUpdateList)) {
            dailyExpensesMapper.updateBatch(dailyExpensesUpdateList);
        }
        return totalAmount;
    }

    private BigDecimal processRenewSubsidyExpenses(ExpenseSaveReqVO createReqVO, ExpenseOrderDO expenseOrderDO,
                                                   String billingMonth, LocalDate actualStart, LocalDate actualEnd) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        List<ExpenseSubsidyDO> subsidyList = expenseSubsidyMapper.selectList(new LambdaQueryWrapperX<ExpenseSubsidyDO>()
                .eq(ExpenseSubsidyDO::getElderId, createReqVO.getElderId())
                .eq(ExpenseSubsidyDO::getDeductionBillMonth, billingMonth)
                .eq(ExpenseSubsidyDO::getStatus, BooleanEnum.FALSE.getValue()));

        List<ExpenseSubsidyDO> subsidyUpdateList = new ArrayList<>();
        for (ExpenseSubsidyDO subsidy : subsidyList) {
            ExpenseItemDO expenseItem = new ExpenseItemDO();
            expenseItem.setExpenseId(null);
            expenseItem.setItemName("长护险抵扣");
            expenseItem.setItemCategoryName("长护险");
            expenseItem.setAmount(subsidy.getAmount().negate());
            expenseItem.setActualAmount(subsidy.getAmount().negate());
            expenseItem.setCount(1);
            expenseItem.setTotalAmount(subsidy.getAmount().negate());
            expenseItem.setType(7);
            expenseItem.setIsMonthlyExpense(BooleanEnum.FALSE.getValue());
            expenseItem.setIsOneTimeFee(BooleanEnum.FALSE.getValue());
            expenseItem.setTenantId(createReqVO.getTenantId());
            expenseItem.setCreateTime(new Date());
            expenseItemMapper.insert(expenseItem);

            ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
            orderItemDO.setExpenseOrderId(expenseOrderDO.getId());
            orderItemDO.setSourceExpenseItemId(expenseItem.getId());
            orderItemDO.setExpenseSource(BusinessConstants.LONG_TERM_CARE_INSURANCE);
            orderItemDO.setCount(1);
            orderItemDO.setItemName("长护险抵扣");
            orderItemDO.setItemCategoryName("长护险");
            orderItemDO.setPrice(subsidy.getAmount());
            orderItemDO.setActualPrice(subsidy.getAmount().negate());
            orderItemDO.setTotalAmount(subsidy.getAmount().negate());
            orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
            orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
            orderItemDO.setCreatedTime(new Date());
            orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            orderItemDO.setType(7);
            orderItemDO.setTenantId(createReqVO.getTenantId());
            orderItemDO.setStartDate(actualStart);
            orderItemDO.setEndDate(actualEnd);
            orderItemDO.setDescription(subsidy.getRemarks());
            expenseOrderItemMapper.insert(orderItemDO);

            subsidy.setStatus(BooleanEnum.TRUE.getValue());
            subsidyUpdateList.add(subsidy);
            totalAmount = totalAmount.add(orderItemDO.getTotalAmount().setScale(2, RoundingMode.DOWN));
        }

        if (CollectionUtil.isNotEmpty(subsidyUpdateList)) {
            expenseSubsidyMapper.updateBatch(subsidyUpdateList);
        }
        return totalAmount;
    }

    private BigDecimal processRenewConsumerVoucherExpenses(ExpenseSaveReqVO createReqVO, ExpenseOrderDO expenseOrderDO,
                                                           String billingMonth, LocalDate actualStart, LocalDate actualEnd) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        List<ElderlyConsumerVouchersDO> consumerVoucherList = elderlyConsumerVouchersMapper.selectList(new LambdaQueryWrapperX<ElderlyConsumerVouchersDO>()
                .eq(ElderlyConsumerVouchersDO::getElderId, createReqVO.getElderId())
                .eq(ElderlyConsumerVouchersDO::getBillingMonth, billingMonth)
                .eq(ElderlyConsumerVouchersDO::getStatus, BooleanEnum.FALSE.getValue()));

        List<ElderlyConsumerVouchersDO> consumerVoucherUpdateList = new ArrayList<>();
        for (ElderlyConsumerVouchersDO consumerVoucher : consumerVoucherList) {
            ExpenseItemDO expenseItem = new ExpenseItemDO();
            expenseItem.setExpenseId(null);
            expenseItem.setItemName("消费券抵扣");
            expenseItem.setItemCategoryName("消费券");
            expenseItem.setAmount(consumerVoucher.getAmount().negate());
            expenseItem.setActualAmount(consumerVoucher.getAmount().negate());
            expenseItem.setCount(1);
            expenseItem.setTotalAmount(consumerVoucher.getAmount().negate());
            expenseItem.setType(7);
            expenseItem.setIsMonthlyExpense(BooleanEnum.FALSE.getValue());
            expenseItem.setIsOneTimeFee(BooleanEnum.FALSE.getValue());
            expenseItem.setTenantId(createReqVO.getTenantId());
            expenseItem.setCreateTime(new Date());
            expenseItemMapper.insert(expenseItem);

            ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
            orderItemDO.setExpenseOrderId(expenseOrderDO.getId());
            orderItemDO.setSourceExpenseItemId(expenseItem.getId());
            orderItemDO.setExpenseSource(BusinessConstants.CONSUMER_VOUCHER);
            orderItemDO.setCount(1);
            orderItemDO.setItemName("消费券抵扣");
            orderItemDO.setItemCategoryName("消费券");
            orderItemDO.setPrice(consumerVoucher.getAmount());
            orderItemDO.setActualPrice(consumerVoucher.getAmount().negate());
            orderItemDO.setTotalAmount(consumerVoucher.getAmount().negate());
            orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
            orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
            orderItemDO.setCreatedTime(new Date());
            orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
            orderItemDO.setType(7);
            orderItemDO.setTenantId(createReqVO.getTenantId());
            orderItemDO.setStartDate(actualStart);
            orderItemDO.setEndDate(actualEnd);
            orderItemDO.setDescription(consumerVoucher.getRemarks());
            expenseOrderItemMapper.insert(orderItemDO);

            consumerVoucher.setStatus(BooleanEnum.TRUE.getValue());
            consumerVoucherUpdateList.add(consumerVoucher);
            totalAmount = totalAmount.add(orderItemDO.getTotalAmount().setScale(2, RoundingMode.DOWN));
        }

        if (CollectionUtil.isNotEmpty(consumerVoucherUpdateList)) {
            elderlyConsumerVouchersMapper.updateBatch(consumerVoucherUpdateList);
        }
        return totalAmount;
    }

    /**
     * 根据费用项创建订单项
     */
    private ExpenseOrderItemDO createOrderItemFromExpenseItem(ExpenseItemDO item, ExpenseSaveReqVO createReqVO, ExpenseOrderDO expenseOrderDO) {
        ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
        orderItemDO.setSourceExpenseItemId(item.getId());
        orderItemDO.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
        orderItemDO.setCount(item.getCount());
        orderItemDO.setItemName(item.getItemName());
        orderItemDO.setExpenseOrderId(expenseOrderDO.getId());
        orderItemDO.setPrice(item.getAmount());
        orderItemDO.setActualPrice(item.getActualAmount());
        orderItemDO.setCreatedTime(new Date());
        orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        orderItemDO.setType(item.getType());
        orderItemDO.setItemCategoryName(item.getItemCategoryName());
        orderItemDO.setTenantId(createReqVO.getTenantId());
        return orderItemDO;
    }

    /**
     * 保存合同信息
     */
    private Long saveContractInfo(ExpenseSaveReqVO createReqVO) {
        ElderlyContractDO contract = createReqVO.getContract();
//        // 通过长者ID查询现有合同
//        ElderlyContractDO dbContract = elderlyContractMapper.selectOne(new LambdaQueryWrapperX<ElderlyContractDO>()
//                .eq(ElderlyContractDO::getElderId, createReqVO.getElderId()));

            // 如果没有找到现有合同，则插入新合同
         contract.setAmount(createReqVO.getTotalAmount());
         contract.setElderId(createReqVO.getElderId());
         contract.setTenantId(createReqVO.getTenantId());
         contract.setCreatedTime(new Date());
         elderlyContractMapper.insert(contract);

        List<ElderlyContractDetailDO> details = contract.getDetails();
        if (CollectionUtil.isNotEmpty(details)) {
            // 插入新的合同明细
            for (ElderlyContractDetailDO detail : details) {
                detail.setId(null); // 清空ID，确保是新插入
                detail.setContractId(contract.getId());
                detail.setCreateDate(LocalDateTime.now());
                elderlyContractDetailMapper.insert(detail);
            }
        }
        return contract.getId();
    }

    /**
     * 检查该长者是否有生成月度账单，避免续约后账单丢失
     * 长者上一个合同的结束月是否小于当前合同开始月，是则不检查
     */
    private void checkElderOrderExist(ExpenseSaveReqVO createReqVO){
        List<ElderlyContractDO> oldContract = elderlyContractMapper.selectList(new LambdaQueryWrapperX<ElderlyContractDO>()
                .eq(ElderlyContractDO::getElderId, createReqVO.getElderId())
                .in(ElderlyContractDO::getStatus, 0,1));
        if(CollectionUtil.isEmpty(oldContract)){
            return;
        }
        YearMonth oldContractEndYearMonth = YearMonth.from(oldContract.get(0).getExpireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
        ElderlyContractDO contract = createReqVO.getContract();
        YearMonth contractBeginYearMonth = YearMonth.from(contract.getBeginTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
        if(oldContractEndYearMonth.isBefore(contractBeginYearMonth)){
            return;
        }
        List<ExpenseOrderDO> expenseOrderDOS = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getElderId, contract.getElderId())
                .eq(ExpenseOrderDO::getBillingMonth, contractBeginYearMonth));
        if(CollectionUtil.isEmpty(expenseOrderDOS)){
            throw exception(ErrorCodeConstants.ELDERLY_RENEW_ORDER_NOT_EXISTS);
        }
    }

    private void addCheckInApply(ExpenseSaveReqVO createReqVO){
        ElderlyContractDO contract = createReqVO.getContract();
        // 使用 Gson 将对象转换为 JSON 字符串
        Gson gson = new Gson();
        CheckInApplyDO checkInApplyDO = CheckInApplyDO.builder().bedId(createReqVO.getBedId()).elderlyId(createReqVO.getElderId())
                .totalAmount(createReqVO.getTotalAmount()).remark(createReqVO.getRemark())
                .checkInTime(createReqVO.getCheckInTime())
                .checkInDeadlineTime(contract.getExpireTime())
                .nurseLevelId(createReqVO.getNurseLevelId())
                .isPrivateRoom(createReqVO.getIsPrivateRoom())
                .contractJson(gson.toJson(contract))
                .monthlyExpensesJson(gson.toJson(createReqVO.getMonthlyExpenses()))
                .oneTimeExpensesJson(gson.toJson(createReqVO.getOneTimeExpenses()))
                .tenantId(TenantContextHolder.getTenantId())
                .remark(createReqVO.getSpecialCareNotes())
                .stageExpensesJson(gson.toJson(createReqVO.getStageExpenses())).build();
        checkInApplyMapper.insert(checkInApplyDO);
        ElderlyCheckInRecordDO insertBO = recordMapper.selectOne(new LambdaQueryWrapperX<ElderlyCheckInRecordDO>()
                .eq(ElderlyCheckInRecordDO::getElderId, createReqVO.getElderId())
                .orderByDesc(ElderlyCheckInRecordDO::getCreatedTime)
                .last("LIMIT 1"));
        if (null == insertBO) {
            insertBO = new ElderlyCheckInRecordDO();
        }else {
            insertBO.setCurrentFlag(1);
            recordMapper.updateById(insertBO);
        }
        insertBO.setId(null);
        insertBO.setCheckInTime(contract.getBeginTime());
        insertBO.setCreatedTime(new Date());
        insertBO.setElderId(createReqVO.getElderId());
        insertBO.setStatus(2);
        insertBO.setAssociateId(checkInApplyDO.getId());
        insertBO.setCurrentFlag(0);
        insertBO.setTenantId(createReqVO.getTenantId());
        recordMapper.insert(insertBO);
        // 创建业务表单记录（系统审批，审批完成状态）
        BpmBusinessFormCreateReqDTO businessFormDTO = new BpmBusinessFormCreateReqDTO();
        businessFormDTO.setBusinessId(insertBO.getId()); // 使用入住申请ID作为业务ID
        businessFormDTO.setBusinessId2(createReqVO.getElderId()); // 使用长者ID作为业务ID2
        businessFormDTO.setUserId(SecurityFrameworkUtils.getLoginUserId());
        businessFormDTO.setTenantId(createReqVO.getTenantId());
        businessFormDTO.setType(9); // CHECK_IN 类型，对应办理入住
        businessFormDTO.setStatus(5); // 系统审批状态
        businessFormDTO.setCompleteStatus(1); // 已完成状态
        businessFormDTO.setReadStatus(1); // 已读状态
        // 调用 API 创建业务表单
        bpmBusinessFormApi.createBusinessForm(businessFormDTO);
    }

    /**
     * 定金抵扣
     */
    private BigDecimal handleReservation(String elderName,Long expenseOrderId){
        // 预约时，家属不愿意提供身份证，只能通过长者姓名匹配
        ReservationBedDO reservationBedDO = reservationBedMapper.selectOne(new LambdaQueryWrapperX<ReservationBedDO>()
                .eq(ReservationBedDO::getElderName, elderName)
                .eq(ReservationBedDO::getTenantId, TenantContextHolder.getTenantId()));
        if(reservationBedDO == null){
            return BigDecimal.ZERO;
        }
        if(reservationBedDO.getStatus() != 2){
            return BigDecimal.ZERO;
        }
        ReservationDepositDO reservationDepositDO = reservationDepositMapper.selectOne(new LambdaQueryWrapperX<ReservationDepositDO>()
                .eq(ReservationDepositDO::getReservationId, reservationBedDO.getId())
                .eq(ReservationDepositDO::getTenantId, TenantContextHolder.getTenantId()));
        BigDecimal depositAmount = reservationDepositDO.getDepositAmount().negate();
        //生成子账单
        ExpenseOrderItemDO orderItemDO = new ExpenseOrderItemDO();
        orderItemDO.setSourceExpenseItemId(reservationDepositDO.getId());
        orderItemDO.setExpenseSource(BusinessConstants.RESERVATION_DEPOSIT);
        orderItemDO.setCount(1);
        orderItemDO.setItemName("预约床位定金");
        orderItemDO.setExpenseOrderId(expenseOrderId);
        orderItemDO.setPrice(depositAmount);
        orderItemDO.setActualPrice(depositAmount);
        orderItemDO.setTotalAmount(orderItemDO.getActualPrice().multiply(BigDecimal.valueOf(orderItemDO.getCount())).setScale(8, RoundingMode.DOWN));
        orderItemDO.setRoundAmount(orderItemDO.getTotalAmount().setScale(0, RoundingMode.HALF_UP));
        orderItemDO.setRoundTwoDecimalAmount(orderItemDO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
        orderItemDO.setCreatedTime(new Date());
        orderItemDO.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
        orderItemDO.setType(8);
        orderItemDO.setItemCategoryName("定金");
        orderItemDO.setTenantId(TenantContextHolder.getTenantId());
        orderItemDO.setStartDate(reservationDepositDO.getCreateTime().toLocalDate());
        orderItemDO.setEndDate(reservationDepositDO.getCreateTime().toLocalDate());
        expenseOrderItemMapper.insert(orderItemDO);
        return depositAmount;
    }
}