package com.xinelu.applet.service.appletlogin.impl;


import com.xinelu.applet.dto.appletlogin.AppointmentConsumableDTO;
import com.xinelu.applet.dto.appletlogin.AppointmentInfoDTO;
import com.xinelu.applet.dto.appletlogin.StationItemInfoDTO;
import com.xinelu.applet.mapper.appletlogin.AppletLoginMapper;
import com.xinelu.applet.service.appletlogin.AppletLoginService;
import com.xinelu.applet.utils.AppletAccessTokenUtil;
import com.xinelu.applet.vo.appletlogin.NurserStationItemConsumableVO;
import com.xinelu.applet.vo.appletlogin.NurserStationItemInfoVO;
import com.xinelu.applet.vo.appletlogin.PatientAndPersonFlagVO;
import com.xinelu.applet.vo.nearbynursingstation.PoserInfoHomeVO;
import com.xinelu.common.config.AppletChatConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.entity.AppletLoginVO;
import com.xinelu.common.entity.AppletPhoneVO;
import com.xinelu.common.enums.*;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.AppletChatUtil;
import com.xinelu.common.utils.DateUtils;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.common.utils.bean.BeanUtils;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.appointmentorderdetails.AppointmentOrderDetails;
import com.xinelu.manage.domain.patientinfo.PatientInfo;
import com.xinelu.manage.domain.sysarea.SysArea;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.appointmentorderdetails.AppointmentOrderDetailsMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.sysarea.SysAreaMapper;
import com.xinelu.manage.vo.patientinfo.PatientInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description 微信小程序登录注册业务层实现类
 * @Author 纪寒
 * @Date 2022-09-02 10:55:29
 * @Version 1.0
 */
@Service
@Slf4j
public class AppletLoginServiceImpl implements AppletLoginService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private AppletChatConfig appletChatConfig;
    @Resource
    private AppletLoginMapper appletLoginMapper;
    @Resource
    private PatientInfoMapper patientInfoMapper;
    @Resource
    private AppointmentOrderMapper appointmentOrderMapper;
    @Resource
    private AppointmentOrderDetailsMapper appointmentOrderDetailsMapper;
    @Resource
    private AppletAccessTokenUtil appletAccessTokenUtil;


    /**
     * 返回成功状态码
     */
    private static final int SUCCESS_CODE = 0;

    /**
     * 返回成功状态码
     */
    private static final String OK = "ok";

    @Resource
    private SysAreaMapper sysAreaMapper;

    /**
     * 提前预约时间半天标识
     */
    private static final String HALF_DAY = "HALF_DAY";

    /**
     * 提前预约时间一天标识
     */
    private static final String ONE_DAY = "ONE_DAY";

    /**
     * 获取微信小程序access_token错误码
     */
    private static final int ERROR_ACCESS_CODE = 40001;


    /**
     * 根据登录凭证获取用户的登录信息
     *
     * @param loginCode 登录凭证
     * @param phoneCode 获取手机号登录凭证
     * @return 微信用户登录信息
     */
    @Override
    public AjaxResult appletLogin(String loginCode, String phoneCode) {
        //根据code获取用户的微信unionId以及openId等信息
        AppletLoginVO appletLoginInfo = AppletChatUtil.getAppletLoginInfo(appletChatConfig.getAppletId(), appletChatConfig.getSecret(), loginCode, appletChatConfig.getGrantType());
        if (Objects.isNull(appletLoginInfo)) {
            return AjaxResult.error("获取微信小程序用户信息失败");
        }
        if (Objects.nonNull(appletLoginInfo.getErrcode()) && appletLoginInfo.getErrcode() != SUCCESS_CODE) {
            return AjaxResult.error("获取微信小程序用户信息失败，失败信息为：" + appletLoginInfo.getErrmsg());
        }
        //获取微信accessToken
        String accessToken;
        String accessTokenKey = Constants.NURSE_STATION_APPLET_ACCESS_TOKEN + "accessToken";
        //从Redis中取出accessToken
        Object object = redisTemplate.opsForValue().get(accessTokenKey);
        if (Objects.isNull(object)) {
            //没有，获取accessToken
            accessToken = appletAccessTokenUtil.getAppletAccessToken();
        } else {
            accessToken = (String) object;
        }
        //获取用户手机号
        AppletPhoneVO appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
        if (Objects.isNull(appletPhoneInfo)) {
            return AjaxResult.error("获取用户手机号失败");
        }
        if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
            //当前Redis缓存中的access_token无效直接删除
            if (Objects.nonNull(object)) {
                redisTemplate.delete(accessTokenKey);
                //删除之后重新获取获取accessToken
                accessToken = appletAccessTokenUtil.getAppletAccessToken();
                appletPhoneInfo = AppletChatUtil.getAppletPhoneInfo(phoneCode, accessToken);
                if (Objects.isNull(appletPhoneInfo)) {
                    return AjaxResult.error("获取用户手机号失败");
                }
                if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == ERROR_ACCESS_CODE) {
                    return AjaxResult.error("登录失败！");
                }
            }
        }
        if (StringUtils.isNotBlank(appletPhoneInfo.getErrmsg()) && !OK.equals(appletPhoneInfo.getErrmsg())) {
            return AjaxResult.error("获取用户手机号失败，失败信息为：" + appletPhoneInfo.getErrmsg());
        }
        //根据手机号和openid判断当前用户是否存在
        String phone = StringUtils.isBlank(appletPhoneInfo.getPhoneInfo().getPhoneNumber()) ? "" : appletPhoneInfo.getPhoneInfo().getPhoneNumber();
        String openId = StringUtils.isBlank(appletLoginInfo.getOpenid()) ? "" : appletLoginInfo.getOpenid();
        PatientInfoVO patientInfoByPhone = appletLoginMapper.getPatientInfoByPhone(phone, openId);
        PatientAndPersonFlagVO appletParent = new PatientAndPersonFlagVO();
        //判断首页是否显示“护理员小程序”跳转的链接，非护理员用户不显示跳转链接
        if (Objects.nonNull(patientInfoByPhone) && Objects.nonNull(patientInfoByPhone.getPersonCount()) && patientInfoByPhone.getPersonCount() > 0) {
            appletParent.setPersonLoginFlag(Boolean.TRUE);
        } else {
            appletParent.setPersonLoginFlag(Boolean.FALSE);
        }
        //会员信息为空新增个人信息
        if (Objects.isNull(patientInfoByPhone)) {
            appletParent.setOpenid(openId);
            appletParent.setPhone(phone);
            appletParent.setCreateTime(LocalDateTime.now());
            appletParent.setAreaCode("");
            patientInfoMapper.insertAppletLoginPatientInfo(appletParent);
            appletParent.setId(appletParent.getId());
            return AjaxResult.success(appletParent);
        }
        //更新用户的openid等微信标识信息
        appletParent.setId(patientInfoByPhone.getId());
        appletParent.setOpenid(openId);
        appletParent.setPhone(StringUtils.isBlank(patientInfoByPhone.getPhone()) ? "" : patientInfoByPhone.getPhone());
        appletParent.setUpdateTime(LocalDateTime.now());
        patientInfoMapper.updatePatientInfo(appletParent);
        return AjaxResult.success(appletParent);
    }

    /**
     * 根据微信用户的patientId查询用户是否注册
     *
     * @param patientId 用户id主键
     * @return 用户信息
     */
    @Override
    public AjaxResult getPatientInfoByPatientId(Long patientId) {
        PatientInfo patientInfo = appletLoginMapper.getPatientInfoByPatientId(patientId);
        if (Objects.isNull(patientInfo)) {
            return AjaxResult.error("当前用户未认证个人信息，请先认证个人信息！");
        }
        return AjaxResult.success(patientInfo);
    }

    /**
     * 根据护理站id和护理站项目id查询对应的护理项目信息
     *
     * @param itemInfoDTO 输入参数
     * @return 护理站项目集合
     */
    @Override
    public AjaxResult getStationItemAndConsumableInfo(StationItemInfoDTO itemInfoDTO) {
        //查询护理站项目信息
        NurserStationItemInfoVO nurserStationItemInfo = appletLoginMapper.getNurserStationItemAndPoser(itemInfoDTO.getStationId(), itemInfoDTO.getStationItemId(), itemInfoDTO.getStationItemPriceId());
        if (Objects.isNull(nurserStationItemInfo)) {
            return AjaxResult.error("未查询到当前护理项目信息！");
        }
        //筛选出护理项目的海报
        List<PoserInfoHomeVO> poserInfoList = nurserStationItemInfo.getPoserInfoList().stream().filter(Objects::nonNull).filter(item -> StringUtils.isNotBlank(item.getModuleType()) && item.getModuleType().equals(PoserModuleTypeEnum.NURSE_ITEM_MODULE.getInfo())).collect(Collectors.toList());
        nurserStationItemInfo.setPoserInfoList(poserInfoList);
        //护理耗材总价格
        BigDecimal consumableTotalPrice = BigDecimal.ZERO;
        //查询护理站项目耗材信息
        List<NurserStationItemConsumableVO> itemConsumableList = appletLoginMapper.getItemConsumableList(itemInfoDTO.getStationId(), itemInfoDTO.getStationItemId());
        if (CollectionUtils.isNotEmpty(itemConsumableList)) {
            //计算护理项目价格 = 数量 * 单价
            itemConsumableList.forEach(item -> {
                if (Objects.nonNull(item.getConsumablePrice()) && Objects.nonNull(item.getConsumableCount())) {
                    item.setConsumablePrice(item.getConsumablePrice().multiply(BigDecimal.valueOf(item.getConsumableCount())).setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            });
            consumableTotalPrice = itemConsumableList.stream().filter(item -> Objects.nonNull(item.getConsumablePrice())).map(NurserStationItemConsumableVO::getConsumablePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            nurserStationItemInfo.setItemConsumableList(itemConsumableList);
        }
        //耗材总价格
        nurserStationItemInfo.setConsumableTotalPrice(consumableTotalPrice);
        //应付总金额 = 护理项目价格 + 耗材总价格
        BigDecimal nurseItemPrice = Objects.isNull(nurserStationItemInfo.getNurseItemPrice()) ? BigDecimal.ZERO : nurserStationItemInfo.getNurseItemPrice();
        nurserStationItemInfo.setTotalPrice(nurseItemPrice.add(consumableTotalPrice).setScale(2, BigDecimal.ROUND_HALF_UP));
        return AjaxResult.success(nurserStationItemInfo);
    }

    /**
     * 预约提交方法
     *
     * @param dto 输入参数
     * @return 预约结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult nurseAppointment(AppointmentInfoDTO dto) {
        //判断当前用户新是否存在
        PatientInfoVO patientInfoById = patientInfoMapper.getPatientInfoById(dto.getPatientId());
        if (Objects.isNull(patientInfoById)) {
            return AjaxResult.error("当前用户信息不存在，无法预约！");
        }
        //校验预约服务时间
        AjaxResult appointmentTimeResult = checkAppointmentTime(dto);
        if (Objects.nonNull(appointmentTimeResult)) {
            return appointmentTimeResult;
        }
        //更新人员表的失能情况
        patientInfoMapper.updatePatientDisabling(dto.getPatientId(), dto.getDisablingCondition(), StringUtils.isBlank(dto.getDisablingReason()) ? " " : dto.getDisablingReason());
        //校验当前预约时间点是否已经达到预约人数上限
        if (Objects.nonNull(dto.getAppointmentLimitCount())) {
            //获取当前护理项目预约剩余次数
            RedisAtomicLong remainingAppointmentCount = getAppointmentLimitCount(dto);
            if (remainingAppointmentCount.get() <= 0L) {
                return AjaxResult.error("当前预约时间已达到今日预约人数上限，无法进行预约！");
            }
            try {
                //预约次数减一
                long appointCount = remainingAppointmentCount.decrementAndGet();
                if (appointCount < 0L) {
                    return AjaxResult.error("当前预约时间已达到今日预约人数上限，无法进行预约！");
                }
                //新增预约订单主表信息
                String orderNo = StringUtils.fillZeroByPatientId(dto.getPatientId(), 5) + System.nanoTime();
                this.addAppointmentOrderInfo(dto, orderNo);
                //新增预约订单明细表信息
                this.addAppointOrderDetailsAndConsumableInfo(dto, orderNo);
                return AjaxResult.success(appointmentOrderMapper.getAppointmentOrderByOrderNo(orderNo));
            } catch (Exception exception) {
                log.error("预约订单接口异常，护理站id：{}，护理项目id：{}，预约次数：{}， 预约时间：{}", dto.getStationId(), dto.getStationItemId(), remainingAppointmentCount.get(), dto.getServiceDate() + "_" + dto.getServiceStartTime());
                //预约次数加一
                remainingAppointmentCount.incrementAndGet();
                throw exception;
            }
        }
        //新增预约订单主表信息
        String orderNo = StringUtils.fillZeroByPatientId(dto.getPatientId(), 5) + System.nanoTime();
        this.addAppointmentOrderInfo(dto, orderNo);
        //新增预约订单明细表信息
        this.addAppointOrderDetailsAndConsumableInfo(dto, orderNo);
        return AjaxResult.success(appointmentOrderMapper.getAppointmentOrderByOrderNo(orderNo));
    }

    /**
     * 根据openid判断当前用户信息是否存在，微信小程序登录页使用
     *
     * @param openId 微信用户的openid
     * @return 护理人列表集合
     */
    @Override
    public AjaxResult existPatientInfo(String openId) {
        PatientInfo patientInfo = appletLoginMapper.getPatientInfoByOpenId(openId);
        if (Objects.nonNull(patientInfo) && StringUtils.isNotBlank(patientInfo.getBindOpenid())) {
            return AjaxResult.success("LOGIN");
        }
        return AjaxResult.success("NOT_LOGIN");
    }

    /**
     * 查询省级区域信息信息
     *
     * @return 省级区域信息集合
     */
    @Override
    public AjaxResult getProvinceAreaInfo() {
        SysArea area = new SysArea();
        area.setAreaLevel(1);
        area.setRemoteSigns(0);
        return AjaxResult.success(sysAreaMapper.selectSysAreaList(area));
    }

    /**
     * 根据父级区域编码查询其下属区域信息
     *
     * @param areaCode 父级区域编码
     * @return 下属区域信息集合
     */
    @Override
    public AjaxResult getSubordinateAreaInfo(String areaCode) {
        //查询出下级区域集合
        return AjaxResult.success(sysAreaMapper.getCityInfoList(areaCode, RemoteSignsEnum.REMOTE.getInfo()));
    }

    /**
     * 校验预约服务时间
     *
     * @param appointmentInfo 预约信息
     * @return com.xinyilu.common.core.domain.AjaxResult 校验结果
     */
    private AjaxResult checkAppointmentTime(AppointmentInfoDTO appointmentInfo) {
        //当前时间点和预约时间点
        LocalTime nowTime = LocalTime.parse(DateTimeFormatter.ofPattern("HH:mm").format(LocalTime.now()));
        LocalTime appointmentTime = appointmentInfo.getServiceStartTime();
        //每天零点时间
        LocalTime zeroTime = LocalTime.parse("00:00");
        //判断当前护理站是否营业
        boolean checkStartTime = appointmentTime.isAfter(appointmentInfo.getMorningOpenStartTime()) && appointmentTime.isBefore(appointmentInfo.getMorningOpenEndTime());
        boolean checkEndTime = appointmentTime.isAfter(appointmentInfo.getAfternoonOpenStartTime()) && appointmentTime.isBefore(appointmentInfo.getAfternoonOpenEndTime());
        boolean morningStartTime = appointmentTime.equals(appointmentInfo.getMorningOpenStartTime());
        boolean afternoonStartTime = appointmentTime.equals(appointmentInfo.getAfternoonOpenStartTime());
        if (BooleanUtils.isFalse(checkStartTime) && BooleanUtils.isFalse(checkEndTime) && !morningStartTime && !afternoonStartTime) {
            return AjaxResult.error("当前预约时间护理站暂未营业，无法进行预约！");
        }
        //当前预约项目时长是提前半天，那么上午的时间都不可预约
        if (StringUtils.isNotBlank(appointmentInfo.getAdvanceAppointDuration()) && HALF_DAY.equals(appointmentInfo.getAdvanceAppointDuration())) {
            if (nowTime.equals(appointmentInfo.getMorningOpenStartTime()) || (nowTime.isAfter(zeroTime) && nowTime.isBefore(appointmentInfo.getMorningOpenEndTime()))) {
                boolean beforeData = appointmentInfo.getServiceDate().isEqual(LocalDate.now()) || appointmentInfo.getServiceDate().isBefore(LocalDate.now());
                boolean beforeTime = appointmentInfo.getServiceStartTime().isBefore(appointmentInfo.getAfternoonOpenStartTime());
                if (BooleanUtils.isTrue(beforeData) && BooleanUtils.isTrue(beforeTime)) {
                    return AjaxResult.error("当前护理项目需要提前半天预约，现在是上午时间，只能预约下午以后的时间！");
                }
            }
            if (nowTime.equals(appointmentInfo.getAfternoonOpenStartTime()) || (nowTime.isAfter(appointmentInfo.getMorningOpenEndTime()) && nowTime.isBefore(appointmentInfo.getAfternoonOpenEndTime()))) {
                //说明当前时间处于下午营业时间，那么当前时间以及之前的时间都不可预约，只能预约明天的时间
                if (appointmentInfo.getServiceDate().isEqual(LocalDate.now()) || appointmentInfo.getServiceDate().isBefore(LocalDate.now())) {
                    return AjaxResult.error("当前护理项目需要提前半天预约，现在是下午时间，只能预约明天以后的时间！");
                }
            }
        }
        //当前预约项目时长是提前一天，那么当天的所有时间点都不可预约
        if (StringUtils.isNotBlank(appointmentInfo.getAdvanceAppointDuration()) && ONE_DAY.equals(appointmentInfo.getAdvanceAppointDuration())) {
            if (appointmentInfo.getServiceDate().isEqual(LocalDate.now()) || appointmentInfo.getServiceDate().isBefore(LocalDate.now())) {
                return AjaxResult.error("当前护理项目需要提前一天预约，无法进行预约！");
            }
        }
        //判断预约时间是否是今天之前的时间，比如当前时间是：2023-02-20 17:00，而预约时间选择的是17:00之前的时间，不可以预约
        if (appointmentInfo.getServiceDate().isEqual(LocalDate.now()) && appointmentInfo.getServiceStartTime().isBefore(nowTime)) {
            return AjaxResult.error("预约时间不能选择当前时间之前的时间，请选择'" + nowTime + "'之后的时间！");
        }
        return null;
    }

    /**
     * 获取当前预约服务项目可预约的剩余次数
     *
     * @param appointmentInfo 预约信息
     * @return com.xinyilu.common.core.domain.AjaxResult 预约剩余次数
     */
    private RedisAtomicLong getAppointmentLimitCount(AppointmentInfoDTO appointmentInfo) {
        RedisAtomicLong appointLimitCount;
        String appointLimitCountKey = Constants.PRE_APPOINTMENT_LIMIT_COUNT_KEY + appointmentInfo.getStationItemId() + "_" + appointmentInfo.getServiceDate() + "_" + appointmentInfo.getServiceStartTime();
        //根据预约时间点查询当前项目的预约订单的数量，并将其放入Redis中进行缓存
        if (!Objects.equals(Boolean.TRUE, redisTemplate.hasKey(appointLimitCountKey))) {
            //当前Redis中没有该时间点的预约数量限制，将其放入到Redis中
            appointLimitCount = new RedisAtomicLong(appointLimitCountKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
            //统计当前护理项目当前预约时间点的预约订单数量
            List<String> orderStatusList = Arrays.asList(OrderStatusEnum.WAIT_PAY.getInfo(), OrderStatusEnum.PAY.getInfo(),
                    OrderStatusEnum.WAIT_DISPATCH.getInfo(), OrderStatusEnum.NOT_FINISH.getInfo(), OrderStatusEnum.COMPLETE.getInfo(),
                    OrderStatusEnum.WAIT_REFUND.getInfo(), OrderStatusEnum.EVALUATED.getInfo());
            Integer appointOrderCount = appletLoginMapper.getAppointOrderCountByIdAndTime(appointmentInfo.getStationItemId(), appointmentInfo.getServiceDate(), appointmentInfo.getServiceStartTime(), orderStatusList);
            if (Objects.isNull(appointOrderCount)) {
                appointOrderCount = 0;
            }
            //将领取数量放入Redis中
            if (appointLimitCount.compareAndSet(0, appointmentInfo.getAppointmentLimitCount() - appointOrderCount)) {
                //过期时间，在当前时间的基础上在增加24小时，因为存在24小时未支付的订单需要处理Redis中的预约订单次数
                LocalDateTime expireTime = appointmentInfo.getServiceDate().atTime(23, 59, 59).plusHours(24);
                appointLimitCount.expireAt(DateUtils.localDateTimeToDate(expireTime));
            }
        } else {
            appointLimitCount = new RedisAtomicLong(appointLimitCountKey, Objects.requireNonNull(redisTemplate.getConnectionFactory()));
        }
        return appointLimitCount;
    }

    /**
     * 新增预约订单主表信息
     *
     * @param dto     输入参数
     * @param orderNo 订单编号
     */
    private void addAppointmentOrderInfo(AppointmentInfoDTO dto, String orderNo) {
        //新增预约订单主表信息
        AppointmentOrder appointmentOrder = new AppointmentOrder();
        appointmentOrder.setPatientId(dto.getPatientId());
        appointmentOrder.setOrderNo(orderNo);
        appointmentOrder.setTotalPrice(dto.getTotalPrice());
        appointmentOrder.setOrderStatus(OrderStatusEnum.WAIT_PAY.getInfo());
        appointmentOrder.setRemark(StringUtils.isBlank(dto.getRemark()) ? "" : dto.getRemark());
        appointmentOrder.setDelFlag(0);
        appointmentOrder.setOrderType(AppointmentOrderTypeEnum.OTHER.getInfo());
        appointmentOrder.setOrderChannel(dto.getOrderChannel());
        appointmentOrder.setCreateTime(LocalDateTime.now());
        appointmentOrder.setOrderCommissionAmount(Objects.isNull(dto.getOrderCommissionAmount()) ? null : dto.getOrderCommissionAmount());
        int insertOrderCount = appointmentOrderMapper.insertAppointmentOrder(appointmentOrder);
        if (insertOrderCount <= 0) {
            log.info("新增预约订单主表失败，失败原因：[{}]", appointmentOrder);
            throw new ServiceException("预约护理信息失败，请联系管理员！");
        }
    }

    /**
     * 新增预约订单明细表和耗材包表信息
     *
     * @param dto     输入参数
     * @param orderNo 订单编号
     */
    private void addAppointOrderDetailsAndConsumableInfo(AppointmentInfoDTO dto, String orderNo) {
        AppointmentOrderDetails orderDetails = new AppointmentOrderDetails();
        BeanUtils.copyProperties(dto, orderDetails);
        orderDetails.setNurseStationItemId(dto.getStationItemId());
        orderDetails.setNurseStationItemPriceId(Objects.isNull(dto.getStationItemPriceId()) ? null : dto.getStationItemPriceId());
        orderDetails.setOrderNo(orderNo);
        orderDetails.setOrderStatus(OrderStatusEnum.WAIT_PAY.getInfo());
        orderDetails.setAppointmentStatus(AppointmentStatusEnum.APPOINTMENT_YES.getValue());
        orderDetails.setItemServeDurationUnit(dto.getServeDurationUnit());
        orderDetails.setDelFlag(0);
        orderDetails.setCreateTime(LocalDateTime.now());
        //计算耗材包总价格
        if (CollectionUtils.isNotEmpty(dto.getOrderConsumableList())) {
            BigDecimal consumableTotalPrice = dto.getOrderConsumableList().stream().filter(item -> Objects.nonNull(item.getConsumablePrice()))
                    .map(AppointmentConsumableDTO::getConsumablePrice).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP);
            orderDetails.setConsumableTotalPrice(consumableTotalPrice);
        }
        int insertOrderDetailsCount = appointmentOrderDetailsMapper.insertAppointmentOrderDetails(orderDetails);
        if (insertOrderDetailsCount <= 0) {
            log.info("新增预约订明细表失败，失败原因：[{}]", orderDetails);
            throw new ServiceException("预约护理信息失败，请联系管理员！");
        }
        //新增预约订单耗材包表信息
        if (CollectionUtils.isNotEmpty(dto.getOrderConsumableList())) {
            List<AppointmentConsumableDTO> orderConsumableList = dto.getOrderConsumableList();
            orderConsumableList.forEach(item -> item.setAppointOrderDetailsId(orderDetails.getId()));
            int orderConsumableCount = appletLoginMapper.insertBatchOrderConsumable(orderConsumableList);
            if (orderConsumableCount <= 0) {
                log.info("新增预约订单耗材信息表失败，失败原因：[{}]", dto.getOrderConsumableList());
                throw new ServiceException("预约护理信息失败，请联系管理员！");
            }
        }
    }


}
