/*
 *    Copyright (c) 2018-2025, hnqz All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: hnqz
 */
package com.qunzhixinxi.hnqz.admin.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qunzhixinxi.hnqz.admin.api.constant.CacheConstants;
import com.qunzhixinxi.hnqz.admin.api.entity.SysDept;
import com.qunzhixinxi.hnqz.admin.api.entity.SysUser;
import com.qunzhixinxi.hnqz.admin.config.TaxNotifyConfig;
import com.qunzhixinxi.hnqz.admin.entity.*;
import com.qunzhixinxi.hnqz.admin.entity.input.SettleAmountMonitorInput;
import com.qunzhixinxi.hnqz.admin.entity.input.SettleNoteStatusOutput;
import com.qunzhixinxi.hnqz.admin.entity.output.SettleAmountMonitorOutput;
import com.qunzhixinxi.hnqz.admin.entity.output.WmTaskSettleNoteOutput;
import com.qunzhixinxi.hnqz.admin.enums.ChannelEnum;
import com.qunzhixinxi.hnqz.admin.enums.SubjectTypeEnum;
import com.qunzhixinxi.hnqz.admin.mapper.WmScorePackageMapper;
import com.qunzhixinxi.hnqz.admin.mapper.WmScorePackageSettleNoteMapper;
import com.qunzhixinxi.hnqz.admin.service.*;
import com.qunzhixinxi.hnqz.common.core.util.R;
import com.qunzhixinxi.hnqz.common.ding.config.DingConfig;
import com.qunzhixinxi.hnqz.common.ding.entity.EmployPayResponse;
import com.qunzhixinxi.hnqz.common.ding.entity.EmployPayResultSuccessItem;
import com.qunzhixinxi.hnqz.common.ding.entity.EmployPayResultfailItem;
import com.qunzhixinxi.hnqz.common.ding.enums.DingEnum;
import com.qunzhixinxi.hnqz.common.ding.service.DingService;
import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
import com.qunzhixinxi.hnqz.common.taxhelper.config.TaxHelperConfig;
import com.qunzhixinxi.hnqz.common.taxhelper.entity.model.TaxHelperSettlementModel;
import com.qunzhixinxi.hnqz.common.taxhelper.entity.request.TaxHelperSettlementRequest;
import com.qunzhixinxi.hnqz.common.taxhelper.entity.response.TaxHelperResponse;
import com.qunzhixinxi.hnqz.common.taxhelper.enums.TaxHelperCertStatus;
import com.qunzhixinxi.hnqz.common.taxhelper.service.TaxHelperService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author pigx code generator
 * @date 2021-01-26 15:44:49
 */
@Slf4j
@Service
@AllArgsConstructor
public class WmScorePackageSettleNoteServiceImpl extends ServiceImpl<WmScorePackageSettleNoteMapper, WmScorePackageSettleNote> implements WmScorePackageSettleNoteService {

	private final WmScorePackageSettleNoteMapper noteMapper;
	private final WmScorePackageMapper wmScorePackageMapper;
	private final SysUserService sysUserService;
	private final SysDeptService deptService;
	private final SysDeptSubService sysDeptSubService;
	private final RedisTemplate redisTemplate;
	private final DingService dingService;
	private final WmDaAgentService wmDaAgentService;
	private final WmDaDrugEntService wmDaDrugEntService;
	private final TaxHelperService taxHelperService;
	private final TaxNotifyConfig taxNotifyConfig;
	private final MonitoringIndicatorService monitoringIndicatorService;

	@Override
	public IPage<WmTaskSettleNoteOutput> getWmTaskSettleInfoPage(Page page, WmScorePackageSettleNote note) {
		return noteMapper.getWmTaskSettleInfoPage(page, note);
	}

	/**
	 * 结算包结算列表（分页）
	 *
	 * @param page
	 * @param note
	 * @return
	 */
	@Override
	public IPage<WmTaskSettleNoteOutput> getWmTaskForSettlePage(Page page, WmScorePackageSettleNote note) {
		return noteMapper.getWmTaskForSettlePage(page, note);
	}

	/**
	 * 结算包结算列表
	 *
	 * @param note
	 * @return
	 */
	@Override
	public List<WmTaskSettleNoteOutput> listWmTaskForSettle(WmScorePackageSettleNote note) {
		return noteMapper.listWmTaskForSettle(note);
	}

	@Override
	public SettleNoteStatusOutput selectSettleNoteStatus(String packageId) {
		return noteMapper.selectSettleNoteStatus(packageId);
	}

	@Override
	public R getSettleInfo(WmScorePackageSettleNote note) {

		SysUser user = sysUserService.getById(note.getUserId());
		if (null != note.getId()) {

			note = this.baseMapper.selectById(note.getId());
			note.setRealName(user.getRealname());
			note.setIdCardNumber(user.getIdCardNumber());
			return R.ok(note);
		}
		WmScorePackageSettleNote query = new WmScorePackageSettleNote();
		query.setPackageId(note.getPackageId());
		query.setTaskId(note.getTaskId());
		query.setUserId(note.getUserId());

		List<WmScorePackageSettleNote> noteList = this.baseMapper.selectList(Wrappers.query(query));
		if (CollectionUtils.isNotEmpty(noteList)) {
			if (noteList.size() > 1) {
				return R.failed("结算数据异常，请联系管理员处理");
			}
			query = noteList.get(0);

		} else {
			WmScorePackage wmScorePackage = wmScorePackageMapper.selectById(note.getPackageId());
			BigDecimal amount = new BigDecimal(wmScorePackage.getScore())
					.divide(new BigDecimal(wmScorePackage.getTaskNum()), 2, BigDecimal.ROUND_HALF_UP);
			query.setSettleAmount(amount);
			query.setSubType(wmScorePackage.getSubType());
		}
		query.setRealName(user.getRealname());
		query.setIdCardNumber(user.getIdCardNumber());

		return R.ok(query);
	}


	@Override
	public R saveSettleInfo(WmScorePackageSettleNote note) {

		SysUser user = sysUserService.getById(note.getUserId());

		if (StringUtils.isEmpty(user.getIdCardNumber())) {
			return R.failed(user.getRealname() + "未认证，不能发起结算");
		}
		if ("0".equals(note.getSubType())) {
			if (!Objects.equals(user.getRljCertStatus(), DingEnum.CER_STATUS_1.getType())) {
				return R.failed(user.getRealname() + "未认证，不能发起结算");
			}
		}
		if ("1".equals(note.getSubType())) {
			if (!Objects.equals(user.getCertStatus(), TaxHelperCertStatus.CERT.getCode())) {
				return R.failed(user.getRealname() + "人员未认证或未绑卡，不能结算");
			}
		}

		SysDeptSub condition = new SysDeptSub();
		condition.setDeptId(user.getDeptId());
		condition.setSubjectType(note.getSubType());
		condition.setEnableFlag(SubjectTypeEnum.ENABLE_FLAG_TRUE.getCode());
		SysDeptSub sysDeptSub = sysDeptSubService.getOne(Wrappers.query(condition));

		if (null == sysDeptSub || StringUtils.isBlank(sysDeptSub.getAppId())) {
			return R.failed("人员所在机构未配置结算信息");
		}

		List<String> idCard = new ArrayList<>();
		List<String> userIds = new ArrayList<>();
		List<Integer> ids = new ArrayList<>();
		idCard.add(user.getIdCardNumber());
		userIds.add(user.getUserId() + "");
		if (null != note.getId()) {
			ids.add(note.getId());
		}
		SettleAmountMonitorInput monitorInput = SettleAmountMonitorInput.fromIdCard(idCard, ids, note.getSubType());
		List<SettleAmountMonitorOutput> monitorOutputList = sysDeptSubService.getSettleAmountMonitor(monitorInput);

		SettleAmountMonitorInput deptMonitorInput = SettleAmountMonitorInput.fromUserId(userIds, ids, note.getSubType());
		List<SettleAmountMonitorOutput> deptAmountMonitor = sysDeptSubService.getDeptAmountMonitor(deptMonitorInput);


		SettleAmountMonitorOutput monitorOutput = monitorOutputList.stream().filter(item -> item.getIdCardNumber()
				.equals(user.getIdCardNumber())).findFirst().orElse(null);

		SettleAmountMonitorOutput deptMonitorOutput = deptAmountMonitor.stream().filter(item -> item.getUserId()
				.equals(note.getUserId())).findFirst().orElse(null);

		MonitoringIndicator monitoringIndicator = monitoringIndicatorService.getBySubType(note.getSubType());
		BigDecimal deptLimit = sysDeptSub.getLimitAmount();
		BigDecimal monitoringLimit = monitoringIndicator.getLimitAmount();
		BigDecimal monitorAmount = note.getSettleAmount();
		BigDecimal deptMonitorAmount = note.getSettleAmount();
		if (null != monitorOutput) {
			monitorAmount = monitorAmount.add(monitorOutput.getTotalAmount());
		}
		if (null != deptMonitorOutput) {
			deptMonitorAmount = deptMonitorAmount.add(deptMonitorOutput.getTotalAmount());
		}
		if (null != deptLimit) {
			if (deptMonitorAmount.compareTo(deptLimit) > 0) {
				return R.failed(note.getRealName() + "：超过当月限额");
			}
		}
		if (null != monitoringLimit) {
			if (monitorAmount.compareTo(monitoringLimit) > 0) {
				return R.failed(note.getRealName() + "：超过结算渠道限额");
			}
		}

		LocalDateTime localDateTime = LocalDateTime.now();
		if (null == note.getId()) {

			WmScorePackageSettleNote entity = new WmScorePackageSettleNote();
			entity.setSubType(note.getSubType());
			entity.setInvoiceType(note.getInvoiceType());
			entity.setCategoryName(note.toCategoryName());
			entity.setSettleAmount(note.getSettleAmount());
			entity.setDiscount(new BigDecimal(1));
			entity.setPackageId(note.getPackageId());
			entity.setTaskId(note.getTaskId());
			entity.setUserId(note.getUserId());
			String settleNo = UUID.randomUUID().toString().replace("-", "");
			entity.setSettleNo(settleNo);
			entity.setSettleNoteStatus(0);
			entity.setCreateTime(localDateTime);
			entity.setUpdateTime(localDateTime);
			entity.setIdCardNumber(user.getIdCardNumber());
			this.baseMapper.insert(entity);
		} else {
			WmScorePackageSettleNote oldData = this.baseMapper.selectById(note.getId());

			if (0 != oldData.getSettleNoteStatus()) {

				return R.failed("状态异常，不能修改");
			}
			WmScorePackageSettleNote updateEntity = new WmScorePackageSettleNote();
			updateEntity.setId(note.getId());
			updateEntity.setSubType(note.getSubType());
			updateEntity.setInvoiceType(note.getInvoiceType());
			updateEntity.setCategoryName(note.getCategoryName());
			updateEntity.setSettleAmount(note.getSettleAmount());
			updateEntity.setUpdateTime(localDateTime);
			updateEntity.setIdCardNumber(user.getIdCardNumber());
			this.baseMapper.updateById(updateEntity);
		}

		return R.ok();
	}

	@Override
	public R subSettleInfo(WmScorePackageSettleNote note) {

		SysUser user = sysUserService.getById(note.getUserId());

		if (StringUtils.isEmpty(user.getIdCardNumber())) {
			return R.failed(user.getRealname() + "未认证，不能发起结算");
		}
		if ("0".equals(note.getSubType())) {
			if (!Objects.equals(user.getRljCertStatus(), DingEnum.CER_STATUS_1.getType())) {
				return R.failed(user.getRealname() + "未认证，不能发起结算");
			}
		}
		if ("1".equals(note.getSubType())) {
			if (!Objects.equals(user.getCertStatus(), TaxHelperCertStatus.CERT.getCode())) {
				return R.failed(user.getRealname() + "人员未认证或未绑卡，不能结算");
			}
		}

		SysDeptSub condition = new SysDeptSub();
		condition.setDeptId(user.getDeptId());
		condition.setSubjectType(note.getSubType());
		condition.setEnableFlag(SubjectTypeEnum.ENABLE_FLAG_TRUE.getCode());
		SysDeptSub sysDeptSub = sysDeptSubService.getOne(Wrappers.query(condition));

		if (null == sysDeptSub || StringUtils.isBlank(sysDeptSub.getAppId())) {
			return R.failed("人员所在机构未配置结算信息");
		}

		List<String> idCard = new ArrayList<>();
		List<String> userIds = new ArrayList<>();
		List<Integer> ids = new ArrayList<>();
		idCard.add(user.getIdCardNumber());
		userIds.add(user.getUserId() + "");
		if (null != note.getId()) {
			ids.add(note.getId());
		}
		SettleAmountMonitorInput monitorInput = SettleAmountMonitorInput.fromIdCard(idCard, ids, note.getSubType());
		List<SettleAmountMonitorOutput> monitorOutputList = sysDeptSubService.getSettleAmountMonitor(monitorInput);

		SettleAmountMonitorInput deptMonitorInput = SettleAmountMonitorInput.fromUserId(userIds, ids, note.getSubType());
		List<SettleAmountMonitorOutput> deptAmountMonitor = sysDeptSubService.getDeptAmountMonitor(deptMonitorInput);


		SettleAmountMonitorOutput monitorOutput = monitorOutputList.stream().filter(item -> item.getIdCardNumber()
				.equals(user.getIdCardNumber())).findFirst().orElse(null);

		SettleAmountMonitorOutput deptMonitorOutput = deptAmountMonitor.stream().filter(item -> item.getUserId()
				.equals(note.getUserId())).findFirst().orElse(null);

		MonitoringIndicator monitoringIndicator = monitoringIndicatorService.getBySubType(note.getSubType());
		BigDecimal deptLimit = sysDeptSub.getLimitAmount();
		BigDecimal monitoringLimit = monitoringIndicator.getLimitAmount();
		BigDecimal monitorAmount = note.getSettleAmount();
		BigDecimal deptMonitorAmount = note.getSettleAmount();
		if (null != monitorOutput) {
			monitorAmount = monitorAmount.add(monitorOutput.getTotalAmount());
		}
		if (null != deptMonitorOutput) {
			deptMonitorAmount = deptMonitorAmount.add(deptMonitorOutput.getTotalAmount());
		}
		if (null != deptLimit) {
			if (deptMonitorAmount.compareTo(deptLimit) > 0) {
				return R.failed(note.getRealName() + "：超过当月限额");
			}
		}
		if (null != monitoringLimit) {
			if (monitorAmount.compareTo(monitoringLimit) > 0) {
				return R.failed(note.getRealName() + "：超过结算渠道限额");
			}
		}

		WmScorePackageSettleNote updateEntity;
		LocalDateTime localDateTime = LocalDateTime.now();
		if (null != note.getId()) {
			WmScorePackageSettleNote oldData = this.baseMapper.selectById(note.getId());
			if (0 != oldData.getSettleNoteStatus()) {

				return R.failed("状态异常，不能提交");
			}
			updateEntity = new WmScorePackageSettleNote();
			updateEntity.setId(note.getId());
			updateEntity.setSubType(note.getSubType());
			updateEntity.setInvoiceType(note.getInvoiceType());
			updateEntity.setCategoryName(note.toCategoryName());
			updateEntity.setSettleAmount(note.getSettleAmount());
			updateEntity.setSettleNoteStatus(9);
			updateEntity.setSubTime(localDateTime);
			updateEntity.setUpdateTime(localDateTime);
			updateEntity.setIdCardNumber(user.getIdCardNumber());
			this.baseMapper.updateById(updateEntity);
			WmScorePackageSettleNote settleNote = this.baseMapper.selectById(note.getId());

			WmScorePackage wmScorePackage = wmScorePackageMapper.selectById(settleNote.getPackageId());
			wmScorePackage.setSettlementDate(LocalDateTime.now());
			wmScorePackageMapper.updateById(wmScorePackage);
			return R.ok();
		} else {
			WmScorePackageSettleNote entity = new WmScorePackageSettleNote();
			entity.setSubType(note.getSubType());
			entity.setInvoiceType(note.getInvoiceType());
			entity.setCategoryName(note.toCategoryName());
			entity.setSettleAmount(note.getSettleAmount());
			entity.setDiscount(new BigDecimal(1));
			entity.setPackageId(note.getPackageId());
			entity.setTaskId(note.getTaskId());
			entity.setUserId(note.getUserId());
			String settleNo = UUID.randomUUID().toString().replace("-", "");
			entity.setSettleNo(settleNo);
			entity.setSettleNoteStatus(9);

			entity.setCreateTime(localDateTime);
			entity.setSubTime(localDateTime);
			entity.setUpdateTime(localDateTime);
			entity.setIdCardNumber(user.getIdCardNumber());

			this.baseMapper.insert(entity);
		}

		return R.ok();
	}

	@Override
	public R revokeSettle(WmScorePackageSettleNote note) {
		WmScorePackageSettleNote updateEntity;
		if (null != note.getId()) {
			WmScorePackageSettleNote oldData = this.baseMapper.selectById(note.getId());
			if (9 != oldData.getSettleNoteStatus() && 2 != oldData.getSettleNoteStatus()) {

				return R.failed("状态异常，不能回退");
			}
//			updateEntity = new WmScorePackageSettleNote();
//			updateEntity.setId(note.getId());
//			updateEntity.setInvoiceType(note.getInvoiceType());
//			updateEntity.setCategoryName(note.getCategoryName());
//			updateEntity.setSettleAmount(note.getSettleAmount());
//			updateEntity.setSettleNoteStatus(0);
//			this.baseMapper.updateById(updateEntity);
			this.baseMapper.deleteById(note.getId());
			return R.ok();
		}

		WmScorePackageSettleNote query = new WmScorePackageSettleNote();
		if (StringUtils.isNotEmpty(note.getPackageId())) {
			query.setPackageId(note.getPackageId());
		} else {
			return R.failed("批量回退失败，参数异常");
		}
		if (StringUtils.isNotEmpty(note.getUserId())) {
			query.setUserId(note.getUserId());
		}
//		query.setSettleNoteStatus(9);
//		updateEntity = new WmScorePackageSettleNote();
//		updateEntity.setSettleNoteStatus(0);
//		this.baseMapper.update(updateEntity, Wrappers.query(query));
		this.baseMapper.delete(Wrappers.query(query));
		return R.ok();
	}

	@Override
	public R singletSettle(WmScorePackageSettleNote input) {
		WmScorePackageSettleNote note = this.baseMapper.selectById(input.getId());
		WmScorePackage wmScorePackage = wmScorePackageMapper.selectById(note.getPackageId());
		SysDept sysDept = deptService.getById(SecurityUtils.getUser().getDeptId());
		if (9 != note.getSettleNoteStatus() && 2 != note.getSettleNoteStatus()) {
			return R.failed("状态异常，不能结算");
		}
		if (StringUtils.isEmpty(note.getUserId())) {
			return R.failed("数据异常，不能结算");
		}

		/**
		 * 结算配置信息
		 */
		SysDeptSub condition = new SysDeptSub();
		condition.setDeptId(sysDept.getDeptId());
		condition.setSubjectType(note.getSubType());
		condition.setEnableFlag(SubjectTypeEnum.ENABLE_FLAG_TRUE.getCode());
		SysDeptSub sysDeptSub = sysDeptSubService.getOne(Wrappers.query(condition));

		if (null == sysDeptSub || StringUtils.isEmpty(sysDeptSub.getAppId())) {
			return R.failed("机构appId未维护");
		}

		SysUser sysUser = sysUserService.getById(note.getUserId());
		if (redisTemplate.hasKey(CacheConstants.SETTLE_PACKAGE_KEY + note.getId())) {
			return R.failed("结算对象-" + sysUser.getRealname() + "：");
		}
		if (SubjectTypeEnum.TYPE_RENLIJIA.getCode().equals(note.getSubType())) {
			log.info("结算渠道 {}", SubjectTypeEnum.TYPE_RENLIJIA.getDesc());
			if (!DingEnum.CER_STATUS_1.getType().equals(sysUser.getRljCertStatus())) {
				//认证中
				log.info("结算对象- {} ：未认证成功，不能结算", sysUser.getRealname());
				return R.failed("结算对象-" + sysUser.getRealname() + "：未认证成功，不能结算");
			}
		} else {
			log.info("结算渠道 {}", SubjectTypeEnum.TYPE_SHUIBANGYUN.getDesc());
			if (!Objects.equals(sysUser.getCertStatus(), TaxHelperCertStatus.CERT.getCode())) {
				log.info("结算对象- {} ：人员未认证或未绑卡，不能结算", sysUser.getRealname());
				return R.failed("人员未认证或未绑卡，不能结算");
			}
		}

		/**
		 * 发起结算
		 */
		log.info("结算明细noteId： {} 开始结算-----------", note.getId());
		log.info("结算渠道： {} ", note.getSubType());

		if (SubjectTypeEnum.TYPE_RENLIJIA.getCode().equals(note.getSubType())) {
			DingConfig config = new DingConfig();
			config.setAppId(sysDeptSub.getAppId());
			config.setAppSecret(sysDeptSub.getAppSecret());
			config.setQueryUrl(sysDeptSub.getQueryUrl());
			String subjectName = sysDeptSub.getSubjectName();
			return settleByRenLiJia(note, config, wmScorePackage, subjectName);

		} else {
			String taxCode = sysDept.getTaxCode();
			if (StringUtils.isNotEmpty(taxCode)) {
				log.info("税邦云结算开始-获取会员所属企业的统一社会信用代码：{} ", taxCode);
			} else {
				return R.failed("未配置企业的统一社会信用代码");
			}
			TaxHelperConfig config = new TaxHelperConfig();
			config.setAppId(sysDeptSub.getAppId());
			config.setAppSecrete(sysDeptSub.getAppSecret());
			config.setQueryUrl(sysDeptSub.getQueryUrl());

			return settleByShuiBangYun(note, config, wmScorePackage, sysUser, taxCode);
		}

	}

	@Override
	public R batchSettle(WmScorePackageSettleNote input) {

		SysDept sysDept = deptService.getById(SecurityUtils.getUser().getDeptId());

		SysDeptSub condition = new SysDeptSub();
		condition.setDeptId(sysDept.getDeptId());
		condition.setEnableFlag(SubjectTypeEnum.ENABLE_FLAG_TRUE.getCode());
		List<SysDeptSub> subList = sysDeptSubService.list(Wrappers.query(condition));
		Map<String, SysDeptSub> subMap = new HashMap<>();

		subList.forEach(item -> subMap.put(item.getSubjectType(), item));

		String[] ids = input.getIdStr().split(",");
		List<WmScorePackageSettleNote> noteList = new ArrayList<>(ids.length);
		for (int i = 0; i < ids.length; i++) {
			String id = ids[i];
			WmScorePackageSettleNote note = this.baseMapper.selectById(id);
			WmScorePackage wmScorePackage = wmScorePackageMapper.selectById(note.getPackageId());

			if (9 != note.getSettleNoteStatus() && 2 != note.getSettleNoteStatus()) {
				continue;
			}
			if (StringUtils.isEmpty(note.getUserId())) {
				continue;
			}

			/**
			 * 结算配置信息
			 */
			SysDeptSub sysDeptSub = subMap.get(note.getSubType());

			if (null == sysDeptSub || StringUtils.isEmpty(sysDeptSub.getAppId())) {
				return R.failed("机构appId未维护");
			}

			SysUser sysUser = sysUserService.getById(note.getUserId());
			if (redisTemplate.hasKey(CacheConstants.SETTLE_PACKAGE_KEY + note.getId())) {
				return R.failed("结算对象-" + sysUser.getRealname() + "：正在结算，请勿重复结算");
			}
			if (SubjectTypeEnum.TYPE_RENLIJIA.getCode().equals(note.getSubType())) {
				log.info("结算渠道 {}", SubjectTypeEnum.TYPE_RENLIJIA.getDesc());
				if (!DingEnum.CER_STATUS_1.getType().equals(sysUser.getRljCertStatus())) {
					//认证中
					log.info("结算对象- {} ：未认证成功，不能结算", sysUser.getRealname());
					return R.failed("结算对象-" + sysUser.getRealname() + "：未认证成功，不能结算");
				}
			} else {
				log.info("结算渠道 {}", SubjectTypeEnum.TYPE_SHUIBANGYUN.getDesc());
				if (!Objects.equals(sysUser.getCertStatus(), TaxHelperCertStatus.CERT.getCode())) {
					log.info("结算对象- {} ：人员未认证或未绑卡，不能结算", sysUser.getRealname());
					return R.failed("人员未认证或未绑卡，不能结算");
				}
			}

			/**
			 * 发起结算
			 */
			log.info("结算明细noteId： {} 开始结算-----------", note.getId());
			log.info("结算渠道： {} ", note.getSubType());

			if (SubjectTypeEnum.TYPE_RENLIJIA.getCode().equals(input.getSubType())) {
				DingConfig config = new DingConfig();
				config.setAppId(sysDeptSub.getAppId());
				config.setAppSecret(sysDeptSub.getAppSecret());
				config.setQueryUrl(sysDeptSub.getQueryUrl());
				String subjectName = sysDeptSub.getSubjectName();
				settleByRenLiJia(note, config, wmScorePackage, subjectName);

			} else {
				noteList.add(note);
			}
		}

		// 税邦云结算
		if (CollectionUtils.isNotEmpty(noteList)) {
			String taxCode = sysDept.getTaxCode();
			if (StringUtils.isNotEmpty(taxCode)) {
				log.info("税邦云结算开始-获取会员所属企业的统一社会信用代码：{} ", taxCode);
			} else {
				return R.failed("未配置企业的统一社会信用代码");
			}
			SysDeptSub deptSub = subMap.get(SubjectTypeEnum.TYPE_SHUIBANGYUN.getCode());
			TaxHelperConfig config = new TaxHelperConfig();
			config.setAppId(deptSub.getAppId());
			config.setAppSecrete(deptSub.getAppSecret());
			config.setQueryUrl(deptSub.getQueryUrl());
			return settleByTaxHelper(noteList, config, taxCode);
		}
		return R.ok();
	}


	/**
	 * 税帮云结算
	 *
	 * @param noteList 结算记录
	 * @param config   税帮云config
	 * @param taxCode  企业三合一码
	 * @return 结果
	 */
	private R settleByTaxHelper(List<WmScorePackageSettleNote> noteList, TaxHelperConfig config, String taxCode) {

		// 加锁
		List<Integer> noteIdList = noteList.stream().filter(note ->
				redisTemplate.opsForValue().setIfAbsent(
						CacheConstants.SETTLE_PACKAGE_KEY + ":note_id_" + note.getId(),
						noteList, CacheConstants.SETTLE_TIME, TimeUnit.DAYS))
				.mapToInt(WmScorePackageSettleNote::getId).boxed().collect(Collectors.toList());

		// 加锁记录数不等于提交记录数，说明存在在途交易
		if (CollectionUtils.isEmpty(noteIdList)) {
			log.error("当前用户存在其他结算请求");
			return R.failed("当前用户存在其他结算请求");
		} else {
			if (!Objects.equals(noteList.size(), noteIdList.size())) {
				// 删除锁
				redisTemplate.delete(noteIdList);
				log.error("当前用户存在其他结算请求");
				return R.failed("当前用户存在其他结算请求");
			}
		}

		// 开始结算
		TaxHelperSettlementModel taxHelperSettlementModel = new TaxHelperSettlementModel(config);
		taxHelperSettlementModel.setEnterpriseCode(taxCode);
		taxHelperSettlementModel.setExtendFieldNames(Arrays.asList("报告下载地址"));

		Set<String> userIdList = noteList.stream().map(WmScorePackageSettleNote::getUserId).collect(Collectors.toSet());
		taxHelperSettlementModel.setNotifyUrl(taxNotifyConfig.getNotifyUrl() + "/admin/taxhelper/" + String.join("|", userIdList) + "/v1/settlementNotify");

		List<TaxHelperSettlementModel.AbstractArr> abstractArrList = new ArrayList<>();
		Map<String, TaxHelperSettlementModel.DetailedArr> detailArrMap = new HashMap<>();
		noteList.forEach(note -> {
			TaxHelperSettlementModel.DetailedArr detailedArr;
			if (detailArrMap.containsKey(note.getIdCardNumber())) {
				detailedArr = detailArrMap.get(note.getIdCardNumber());
				detailedArr.setInputAmount((BigDecimal.valueOf(detailedArr.getInputAmount())
						.add(note.getSettleAmount())
						.doubleValue()));
			} else {
				detailedArr = new TaxHelperSettlementModel.DetailedArr();
				detailedArr.setIdCard(note.getIdCardNumber());
				detailedArr.setInputAmount(note.getSettleAmount().doubleValue());
				detailedArr.setCategoryName(StringUtils.isEmpty(note.getCategoryName()) ? "专业技术服务" : note.getCategoryName());
				detailArrMap.put(note.getIdCardNumber(), detailedArr);
			}
			TaxHelperSettlementModel.AbstractArr abstractArr = new TaxHelperSettlementModel.AbstractArr();
			abstractArr.setIdCard(note.getIdCardNumber());
			abstractArr.setNumber(1);
			abstractArr.setPrice(note.getSettleAmount().doubleValue());
			abstractArr.setAmount(note.getSettleAmount().doubleValue());
			abstractArr.setExtendField1(taxNotifyConfig.getTaskUrl() + "/#/h5/indexTask?id=" + note.getPackageId() + "&userId=" + note
					.getUserId());
			abstractArrList.add(abstractArr);
		});
		taxHelperSettlementModel.setCount(detailArrMap.size());
		List<TaxHelperSettlementModel.DetailedArr> detailedArrList = new ArrayList<>(detailArrMap.values());
		taxHelperSettlementModel.setDetailedArr(detailedArrList);
		taxHelperSettlementModel.setAbstractArr(abstractArrList);
		TaxHelperSettlementRequest taxHelperSettlementRequest = new TaxHelperSettlementRequest(taxHelperSettlementModel);
		TaxHelperResponse response = taxHelperService.settlement(taxHelperSettlementRequest);
		log.info("税邦云结算： {}", response);
		if (response.success()) {
			noteList.forEach(note -> {
				log.info("税邦云结算提交成功： {}", note.getSettleNo());
				//streamId 获取不到
				if (StringUtils.isEmpty(response.getMessage())) {
					log.info("税邦云结算提交成功 streamId 获取不到： {}", note.getSettleNo());
				}
				note.setUpdateTime(LocalDateTime.now());
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
				// 新增字段streamId
				note.setStreamId(response.getMessage());
				this.baseMapper.updateById(note);
			});
			return R.ok("提交结算成功");
		} else {
			noteList.forEach(note -> {
				log.info("税邦云结算提交失败： {}", note.getSettleNo());
				note.setUpdateTime(LocalDateTime.now());
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
				this.baseMapper.updateById(note);
			});
			return R.ok("结算失败");

		}
	}


	private R settleByShuiBangYun(WmScorePackageSettleNote note,
								  TaxHelperConfig config,
								  WmScorePackage wmScorePackage,
								  SysUser sysUser,
								  String taxCode) {

		/**
		 * 加锁
		 */
		redisTemplate.opsForValue().set(CacheConstants.SETTLE_PACKAGE_KEY + note.getId(),
				note.getId(), CacheConstants.SETTLE_TIME, TimeUnit.DAYS);

		/**
		 * 开始结算
		 */
		TaxHelperSettlementModel taxHelperSettlementModel = new TaxHelperSettlementModel(config);
		taxHelperSettlementModel.setEnterpriseCode(taxCode);

		taxHelperSettlementModel.setExtendFieldNames(Arrays.asList("报告下载地址"));
		taxHelperSettlementModel.setCount(1);

		taxHelperSettlementModel.setNotifyUrl(taxNotifyConfig.getNotifyUrl() + "/admin/taxhelper/" + sysUser.getUserId() + "/v1/settlementNotify");
		TaxHelperSettlementModel.DetailedArr detailedArr = new TaxHelperSettlementModel.DetailedArr();
		detailedArr.setIdCard(sysUser.getIdCardNumber());
		detailedArr.setInputAmount(note.getSettleAmount().doubleValue());
		detailedArr.setCategoryName(note.getCategoryName());
		taxHelperSettlementModel.setDetailedArr(Arrays.asList(detailedArr));

		TaxHelperSettlementModel.AbstractArr abstractArr = new TaxHelperSettlementModel.AbstractArr();

		abstractArr.setIdCard(sysUser.getIdCardNumber());
		abstractArr.setNumber(1);
		abstractArr.setPrice(note.getSettleAmount().doubleValue());
		abstractArr.setAmount(note.getSettleAmount().doubleValue());

		abstractArr.setExtendField1(taxNotifyConfig.getTaskUrl() + "/#/h5/indexTask?id=" + note.getPackageId() + "&userId=" + note
				.getUserId());

		taxHelperSettlementModel.setAbstractArr(Arrays.asList(abstractArr));

		TaxHelperSettlementRequest taxHelperSettlementRequest = new TaxHelperSettlementRequest(taxHelperSettlementModel);

		TaxHelperResponse response = taxHelperService.settlement(taxHelperSettlementRequest);

		log.info("税邦云结算： {}", response);


		if (response.success()) {
			log.info("税邦云结算提交成功： {}", note.getSettleNo());
			//streamId 获取不到
			if (StringUtils.isEmpty(response.getMessage())) {
				log.info("税邦云结算提交成功 streamId 获取不到： {}", note.getSettleNo());
			}
			note.setUpdateTime(LocalDateTime.now());
			note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
			// 新增字段streamId
			note.setStreamId(response.getMessage());
		} else {
			log.info("税邦云结算提交失败： {}", note.getSettleNo());
			note.setUpdateTime(LocalDateTime.now());
			note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());

			log.info("认证状态异常，结算解锁settleNoteId：{}", note.getId());
			redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + note.getId());

		}

		this.baseMapper.updateById(note);

		return R.ok();
	}

	private R settleByRenLiJia(WmScorePackageSettleNote note, DingConfig config, WmScorePackage wmScorePackage, String subjectName) {

		SysUser sysUser = sysUserService.getById(note.getUserId());

		/**
		 * 结算失败过的更新 settleNo
		 */
		if (DingEnum.NOTE_STATUS_FAIL.getType().equals(note.getSettleNoteStatus())) {
			String settleNo = UUID.randomUUID().toString().replace("-", "");
			note.setSettleNo(settleNo);
		}

		/**
		 * 加锁
		 */
		redisTemplate.opsForValue().set(CacheConstants.SETTLE_PACKAGE_KEY + note.getId(),
				note.getId(), CacheConstants.SETTLE_TIME, TimeUnit.DAYS);

		List jsdList = new ArrayList();
		Map jsdMap = new HashMap();
		jsdMap.put("amount", note.getSettleAmount().setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
		jsdMap.put("mobile", sysUser.getPhone());
		jsdMap.put("idCard", sysUser.getIdCardNumber());
		jsdMap.put("name", sysUser.getRealname());
		jsdList.add(jsdMap);

		EmployPayResponse employPayResponse = dingService.pay(config, subjectName,
				note.getSettleNo(), wmScorePackage.getScorePackageName(),
				note.getInvoiceType(), jsdList);

		//提交结算接口失败
		if (!employPayResponse.isSuccess()) {
			log.info("人力家接口调用失败，结算解锁settleNoteId：{}", note.getId());
			redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + note.getId());
			note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());

		} else {
			//结算提交成功数据
			List<EmployPayResultSuccessItem> successResult = employPayResponse.getData().getSuccessResult();
			if (CollectionUtils.isNotEmpty(successResult)) {

				log.info("结算对象-" + sysUser.getRealname() + "：提交结算成功；");
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
			}

			//结算提交失败的数据
			List<EmployPayResultfailItem> failResult = employPayResponse.getData().getFailResult();
			if (CollectionUtils.isNotEmpty(failResult)) {

				log.info("认证状态异常，结算解锁settleNoteId：{}", note.getId());
				redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + note.getId());

				log.info("结算对象-" + sysUser.getRealname() + "，结算失败：" + failResult.get(0).getCheckRemark() + "；");
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
			}
		}

		this.baseMapper.updateById(note);

		return R.ok();
	}

	@Override
	public R settleNotify(String streamId, Integer settleStatus, Boolean izSingle) {


		WmScorePackageSettleNote query = new WmScorePackageSettleNote();
		query.setStreamId(streamId);
		List<WmScorePackageSettleNote> noteList = this.baseMapper.selectList(Wrappers.query(query));
		WmScorePackageSettleNote tmp = noteList.get(0);
		if (CollectionUtils.isNotEmpty(noteList)) {
			log.info("回调成功，流水号{}", streamId);

			List<WmScorePackageSettleNote> updateList = noteList.stream().map(note -> {
				WmScorePackageSettleNote updateEntity = new WmScorePackageSettleNote();
				updateEntity.setId(note.getId());
				updateEntity.setSettleNoteStatus(settleStatus);
				updateEntity.setNotifyTime(LocalDateTime.now());
				return updateEntity;
			}).collect(Collectors.toList());

			this.updateBatchById(updateList);

			WmScorePackage scorePackage = wmScorePackageMapper.selectById(tmp.getPackageId());

			// 遥领不修改
			if (!"1611890566".equals(scorePackage.getSendPackageDeptId())){
				// 更新积分包状态
				log.info("更新积分包状态:{}", tmp);
				WmScorePackage wmScorePackage = new WmScorePackage();
				wmScorePackage.setId(tmp.getPackageId());
				wmScorePackage.setSettleStatus(settleStatus);
				wmScorePackage.setUpdateTime(LocalDateTime.now());
				wmScorePackageMapper.updateById(wmScorePackage);
			}

			// 如果结算失败删除缓存
			if (settleStatus == 2) {
				redisTemplate.delete(CacheConstants.SETTLE_PACKAGE_KEY + tmp.getId());
			}

		} else {
			log.info("回调成功，流水号异常： {}", streamId);
		}

		return R.ok(noteList);
	}

}
