package com.qunzhixinxi.hnqz.admin.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.config.UpmsConfig;
import com.qunzhixinxi.hnqz.admin.entity.*;
import com.qunzhixinxi.hnqz.admin.entity.input.SettleNoteStatusOutput;
import com.qunzhixinxi.hnqz.admin.entity.input.WmScorePackageSettleInput;
import com.qunzhixinxi.hnqz.admin.enums.PackageTypeEnum;
import com.qunzhixinxi.hnqz.admin.enums.SubjectLocation;
import com.qunzhixinxi.hnqz.admin.enums.SubjectTypeEnum;
import com.qunzhixinxi.hnqz.admin.mapper.SysUserMapper;
import com.qunzhixinxi.hnqz.admin.mapper.SysUserSubMapper;
import com.qunzhixinxi.hnqz.admin.mapper.WmPayOffMapper;
import com.qunzhixinxi.hnqz.admin.service.*;
import com.qunzhixinxi.hnqz.common.core.constant.CommonConstants;
import com.qunzhixinxi.hnqz.common.core.util.R;
import com.qunzhixinxi.hnqz.common.ding.config.DingConfig;
import com.qunzhixinxi.hnqz.common.ding.entity.*;
import com.qunzhixinxi.hnqz.common.ding.enums.DingEnum;
import com.qunzhixinxi.hnqz.common.ding.service.DingService;
import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
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.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

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

/**
 * 结算表
 *
 * @author Liujh
 * @date 2020-12-1
 */
@Slf4j
@Service
@AllArgsConstructor
public class WmPayOffServiceImpl extends ServiceImpl<WmPayOffMapper, WmPayOff> implements WmPayOffService {

	private final UpmsConfig upmsConfig;
	private final SysUserMapper sysUserMapper;
	private final SysUserService userService;
	private final SysUserSubMapper sysUserSubMapper;
	private final DingService dingService;
	private final WmScorePackageService wmScorePackageService;
	private final WmTaskService wmTaskService;
	private final WmScorePackageStatusService wmScorePackageStatusService;
	private final WmScorePackageSettleNoteService noteService;
	private final SysDeptService sysDeptService;
	private final SysDeptSubService sysDeptSubService;
	private final RedisTemplate<String, Object> redisTemplate;
	private final MonitoringIndicatorService monitoringIndicatorService;
	private final TaxHelperService taxHelperService;
	private final TaxNotifyConfig taxNotifyConfig;
	private final RestTemplate restTemplate;

	private final MathContext mc = new MathContext(2, RoundingMode.HALF_EVEN);
	private final String GIG_TOKEN_URL = "%s/gig/operation/token?tenantId={tenantId}&action={action}&userId={userId}";
	private final String GIG_SETTLE_URL = "%s/gig/operation/settlement";

	/**
	 * 财务回退操作
	 *
	 * @param input 提交参数
	 * @return 操作结果
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<?> settleBack(WmScorePackageSettleInput input) {
		WmScorePackage wmScorePackage = wmScorePackageService.getById(input.getId());

		if (wmScorePackage.getSettleStatus() != 2 && wmScorePackage.getSettleStatus() != 9) {
			return R.failed("积分包结算状态异常,不能回退");
		}
		WmScorePackage updateEntity = new WmScorePackage();
		updateEntity.setId(wmScorePackage.getId());
		updateEntity.setScorePackageStatus("4");
		updateEntity.setSettleFlag("0");
		wmScorePackageService.updateById(updateEntity);

		WmScorePackageSettleNote deleteQuery = new WmScorePackageSettleNote();
		deleteQuery.setPackageId(input.getId());
		noteService.remove(Wrappers.query(deleteQuery));

		return R.ok(Boolean.TRUE);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<?> saveSettleInfo(List<WmScorePackage> wsList) {

		return R.ok();
	}

	/**
	 * 获取待结算积分包信息
	 *
	 * @param pkgId 积分包id
	 * @return 待结算积分包信息
	 */
	@Override
	public R<?> settleById(String pkgId) {

		WmScorePackage wmScorePackage = wmScorePackageService.getById(pkgId);

		if (!"1".equals(wmScorePackage.getPackageFinishStatus())) {
			return R.failed("积分包状态异常");
		}

		List<WmScorePackageSettleNote> notes = noteService.list(Wrappers.<WmScorePackageSettleNote>lambdaQuery().eq(WmScorePackageSettleNote::getPackageId, pkgId));

		if (CollectionUtils.isEmpty(notes)) {

			List<WmScorePackageStatus> statusList = wmScorePackageStatusService.list(Wrappers.<WmScorePackageStatus>lambdaQuery()
					.eq(WmScorePackageStatus::getPackageId, pkgId)
					.eq(WmScorePackageStatus::getStatus, "2"));

			if (CollectionUtils.isEmpty(statusList)) {
				return R.failed("当前积分包不存在领包记录");
			}

			for (WmScorePackageStatus status : statusList) {
				WmScorePackageSettleNote note = new WmScorePackageSettleNote();
				note.setSettleNo(IdUtil.fastSimpleUUID());
				note.setPackageStatusId(String.valueOf(status.getId()));
				note.setPackageId(status.getPackageId());

				if ("1".equals(wmScorePackage.getPackageType1())) {

					note.setSettleAmount(StringUtils.isEmpty(status.getUserScore()) ? BigDecimal.ZERO : new BigDecimal(status.getUserScore(), mc));

				} else if (PackageTypeEnum.TYPE1_HCP_PACKAGE.val().equals(wmScorePackage.getPackageType1())) {

					// 如果是患者教育，则转换积分值 '分'->'元'
					note.setSettleAmount(StringUtils.isEmpty(status.getUserScore()) ? BigDecimal.ZERO : new BigDecimal(status.getUserScore(), mc).divide(new BigDecimal("100"), mc));

				} else {

					note.setSettleAmount(StringUtils.isEmpty(wmScorePackage.getUserScore()) ? BigDecimal.ZERO : new BigDecimal(wmScorePackage.getUserScore(), mc));

				}

				note.setDiscount(BigDecimal.ONE);
				note.setUserId(status.getUserId());
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_NO.getType());
				SysUser noteUser = sysUserMapper.selectById(status.getUserId());
				note.setRealName(noteUser.getRealname());
				note.setIdCardNumber(noteUser.getIdCardNumber());
				notes.add(note);
			}
		} else {

			notes.forEach(item -> {
				SysUser user = sysUserMapper.selectById(item.getUserId());
				item.setRealName(user.getRealname());
				item.setIdCardNumber(user.getIdCardNumber());
				if (item.getSubjectLocation() != null){
					wmScorePackage.setSubjectLocation(item.getSubjectLocation().name());
				}
			});

			if (StrUtil.isBlank(wmScorePackage.getSubjectLocation())){
				return R.failed("结算积分包未勾选税源地");
			}

		}

		Map<String, Object> resultMap = new HashMap<>(3);

		if (PackageTypeEnum.TYPE1_HCP_PACKAGE.val().equals(wmScorePackage.getPackageType1())) {
			// 如果是患者教育，则转换积分值 '分'->'元'
			wmScorePackage.setUserScore(new BigDecimal(wmScorePackage.getUserScore(), mc).divide(new BigDecimal("100"), mc).toString());
		}
		resultMap.put("wsp", wmScorePackage);
		resultMap.put("notes", notes);
		// 显示实际完成积分值
		resultMap.put("finishScore", "0");

		if (PackageTypeEnum.TYPE1_SCOTE_PACKAGE.val().equals(wmScorePackage.getPackageType1()) || PackageTypeEnum.TYPE1_HCP_PACKAGE.val().equals(wmScorePackage.getPackageType1())) {

			List<WmTask> tasks = wmTaskService.list(Wrappers.<WmTask>lambdaQuery()
					.eq(WmTask::getRealFlag, "0")
					.eq(WmTask::getScorePackageId, wmScorePackage.getId())
					.eq(WmTask::getTaskStatus, "3"));

			BigDecimal total = BigDecimal.ZERO;

			for (WmTask task : tasks) {
				total = total.add(new BigDecimal(task.getScore()));
			}

			if (PackageTypeEnum.TYPE1_HCP_PACKAGE.val().equals(wmScorePackage.getPackageType1())) {
				// 如果是患者教育，则转换积分值 '分'->'元'
				resultMap.put("finishScore", total.divide(new BigDecimal("100"), mc));
			} else {
				resultMap.put("finishScore", total.intValue());
			}
		}

		return R.ok(resultMap);
	}

	/**
	 * 业务提交结算信息到财务
	 *
	 * @param input 输入信息
	 * @return 提交结果
	 */
	@Override
	public R<?> settleSubmit(WmScorePackageSettleInput input) {

		WmScorePackage wmScorePackage = wmScorePackageService.getById(input.getId());

		// 校验基本包状态
		wmScorePackageService.checkPkgToSettle(wmScorePackage);

		List<WmScorePackageSettleNote> notes = input.getNotes();
		SubjectLocation location = input.getSubjectLocation();

		// 校验人员信息
		Set<Integer> userIds = notes.stream().map(WmScorePackageSettleNote::getUserId).map(Integer::valueOf).collect(Collectors.toSet());
		userService.checkUserInfoToSettle(userIds, location);

		// 校验结算
		BigDecimal total = monitoringIndicatorService.settleMonitoringIndicator(notes, location);

		LocalDateTime now = LocalDateTime.now();
		notes.forEach(note -> {
			note.setUpdateTime(now);
			note.setSubTime(now);
			note.setSubType(String.valueOf(location.getGigType().getCode()));
			note.setSubjectLocation(input.getSubjectLocation());
			note.setInvoiceType(input.getInvoiceCategory());
			note.setCategoryName(input.getCategoryName());
			if (null == note.getId()) {
				note.setCreateTime(LocalDateTime.now());
			}
		});

		WmScorePackage updateEntity = new WmScorePackage();
		updateEntity.setInvoiceCategory(input.getInvoiceCategory());
		updateEntity.setSettleAmount(total);
		updateEntity.setId(input.getId());
		updateEntity.setSettleStatus(DingEnum.SETTLE_STATUS_WAIT.getType());
		updateEntity.setScorePackageStatus("5");
		updateEntity.setSettleFlag("1");
		updateEntity.setDescription(input.getDescription());
		updateEntity.setSubType(String.valueOf(location.getGigType().getCode()));
		updateEntity.setLocation(input.getSubjectLocation());
		updateEntity.setSettlementDate(LocalDateTime.now());

		if ("2".equals(wmScorePackage.getPackageType2())) {
			updateEntity.setPackageFinishStatus("1");
			updateEntity.setTaskAddFlag("0");
		}

		wmScorePackageService.updateById(updateEntity);
		noteService.saveOrUpdateBatch(notes);

		return R.ok(Boolean.TRUE);
	}

	/**
	 * 业务保存操作
	 *
	 * @param input 提交信息
	 * @return 保存结果
	 */
	@Override
	public R<?> settleSave(WmScorePackageSettleInput input) {

		List<WmScorePackageSettleNote> notes = input.getNotes();
		SubjectLocation location = input.getSubjectLocation();

		// 校验人员信息
		Set<Integer> userIds = notes.stream().map(WmScorePackageSettleNote::getUserId).map(Integer::valueOf).collect(Collectors.toSet());
		userService.checkUserInfoToSettle(userIds, location);

		// 校验结算
		BigDecimal total = monitoringIndicatorService.settleMonitoringIndicator(notes, location);

		LocalDateTime now = LocalDateTime.now();
		notes.forEach(note -> {
			note.setUpdateTime(now);
			note.setSubTime(now);
			note.setSubType(String.valueOf(location.getGigType().getCode()));
			note.setSubjectLocation(input.getSubjectLocation());
			note.setInvoiceType(input.getInvoiceCategory());
			note.setCategoryName(input.getCategoryName());
			if (null == note.getId()) {
				note.setCreateTime(LocalDateTime.now());
			}
		});
		WmScorePackage updateEntity = new WmScorePackage();
		updateEntity.setInvoiceCategory(input.getInvoiceCategory());
		updateEntity.setSettleAmount(total);
		updateEntity.setId(input.getId());
		updateEntity.setDescription(input.getDescription());
		updateEntity.setSubType(String.valueOf(location.getGigType().getCode()));
		updateEntity.setLocation(input.getSubjectLocation());

		wmScorePackageService.updateById(updateEntity);
		noteService.saveOrUpdateBatch(notes);

		return R.ok(Boolean.TRUE);
	}

	/**
	 * 重新结算
	 *
	 * @param input 结算信息
	 * @return 提交结果
	 */
	@Override
	public R<?> settleReIssueBySubType(WmScorePackageSettleInput input) {

		WmScorePackageSettleNote note = noteService.getById(input.getId());

		WmScorePackage wmScorePackage = wmScorePackageService.getById(note.getPackageId());
		note.setSettleNo(IdUtil.fastSimpleUUID());

		input.setNotes(Collections.singletonList(note));
		input.setInvoiceCategory(note.getInvoiceType());
		input.setCategoryName(input.getCategoryName());
		input.setSubType(note.getSubType());
		input.setScorePackageName(wmScorePackage.getScorePackageName());

		if (!DingEnum.NOTE_STATUS_FAIL.getType().equals(note.getSettleNoteStatus())) {
			return R.failed("状态异常，请刷新页面后再操作");
		}

		// 结算配置信息
		HnqzUser operator = SecurityUtils.getUser();
		SubjectLocation location = input.getSubjectLocation();
		SysDeptSub sysDeptSub = sysDeptSubService.getDeptSub(operator.getDeptId(), location);
		SysDept sysDept = sysDeptService.getById(operator.getDeptId());
		String taxCode = sysDept.getTaxCode();
		if (StringUtils.isEmpty(taxCode)) {
			return R.failed("未配置企业的统一社会信用代码");
		}
		String subType = String.valueOf(location.getGigType().getCode());

		// 人力家
		if (SubjectTypeEnum.TYPE_RENLIJIA.getCode().equals(subType)) {
			return settleByRenLiJia(input, sysDeptSub, operator);
		}
		// 自由职家
		else if (SubjectTypeEnum.TYPE_OLADING.getCode().equals(subType)) {
			return settleByOlading(input, wmScorePackage, taxCode, operator);
		}
		// 税邦云
		else {
			log.info("税邦云结算开始-获取会员所属企业的统一社会信用代码：{} ", taxCode);
			return settleByShuiBangYun(input, sysDeptSub, taxCode, operator);
		}

	}

	/**
	 * 提交结算
	 *
	 * @param input 提交结算信息
	 * @return 提交结果
	 */
	@Override
	public R<?> settleIssueBySubType(WmScorePackageSettleInput input) {

		SubjectLocation location = input.getSubjectLocation();
		WmScorePackage wmScorePackage = wmScorePackageService.getById(input.getId());

		if (wmScorePackage.getSettleStatus() != 2 && wmScorePackage.getSettleStatus() != 9) {
			return R.failed("积分包结算状态异常");
		}

		// 结算配置信息
		HnqzUser operator = SecurityUtils.getUser();
		SysDeptSub sysDeptSub = sysDeptSubService.getDeptSub(operator.getDeptId(), location);
		SysDept sysDept = sysDeptService.getById(sysDeptSub.getDeptId());
		String taxCode = sysDept.getTaxCode();
		if (StringUtils.isEmpty(taxCode)) {
			return R.failed("未配置企业的统一社会信用代码");
		}

		String subType = String.valueOf(location.getGigType().getCode());

		// 人力家
		if (SubjectTypeEnum.TYPE_RENLIJIA.getCode().equals(subType)) {
			return settleByRenLiJia(input, sysDeptSub, operator);
		}
		// 自由职家
		else if (SubjectTypeEnum.TYPE_OLADING.getCode().equals(subType)) {
			return settleByOlading(input, wmScorePackage, taxCode, operator);
		}
		// 税邦云
		else {
			log.info("税邦云结算开始-获取会员所属企业的统一社会信用代码：{} ", taxCode);
			return settleByShuiBangYun(input, sysDeptSub, taxCode, operator);
		}

	}


	/**
	 * 阿拉丁结算操作
	 *
	 * @param input          结算数据
	 * @param wmScorePackage 积分包
	 * @param taxCode        税号
	 * @param operator       操作员
	 * @return 结果
	 */
	private R<?> settleByOlading(WmScorePackageSettleInput input,
								 WmScorePackage wmScorePackage,
								 String taxCode,
								 HnqzUser operator) {

		List<WmScorePackageSettleNote> notes = input.getNotes();
		StringBuilder noticeInfo = new StringBuilder();

		// WmScorePackageSettleNote
		for (WmScorePackageSettleNote note : notes) {
			note.setInvoiceType(input.getInvoiceCategory());
			note.setCategoryName(StrUtil.isNotBlank(input.getCategoryName()) ? input.getCategoryName() : note.getCategoryName());
			note.setSubToGigTime(LocalDateTime.now());
		}
		noteService.updateBatchById(notes);


		for (WmScorePackageSettleNote note : notes) {
			SysUser sysUser = sysUserMapper.selectById(note.getUserId());

			SysUserSub userSub = sysUserSubMapper.selectOne(Wrappers.<SysUserSub>lambdaQuery()
					.eq(SysUserSub::getUserId, sysUser.getUserId())
					.eq(SysUserSub::getSubjectLocation, input.getSubjectLocation())
					.eq(SysUserSub::getDeptId, operator.getDeptId())
			);

			if (userSub == null) {
				log.info("结算对象-" + sysUser.getRealname() + "：认证信息不存在，不能结算");
				return R.failed("结算对象-" + sysUser.getRealname() + "：认证信息不存在，不能结算");
			}

			if (!Objects.equals(userSub.getCertStatus(), DingEnum.CER_STATUS_1.getType())) {
				return R.failed(sysUser.getRealname() + "人员未认证或未绑卡，不能结算");
			}

			if (Boolean.TRUE.equals(redisTemplate.hasKey(CacheConstants.SETTLE_PACKAGE_KEY + note.getId()))) {
				return R.failed("结算对象-" + sysUser.getRealname() + "：正在结算，请勿重复结算");
			}

			if (DingEnum.NOTE_STATUS_SUCCESS.getType().equals(note.getSettleNoteStatus())) {
				log.info("结算对象-" + sysUser.getRealname() + "：已结算，请勿重复结算");
				return R.failed("结算对象-" + sysUser.getRealname() + "：已结算，请勿重复结算");
			}
			if (DingEnum.NOTE_STATUS_SUBMIT.getType().equals(note.getSettleNoteStatus())) {
				log.info("结算对象-" + sysUser.getRealname() + "：已提交，请等待耐心结算结果");
				return R.failed("结算对象-" + sysUser.getRealname() + "：已提交，请等待耐心结算结果");
			}
		}

		for (WmScorePackageSettleNote note : notes) {
			// 加锁
			redisTemplate.opsForValue().set(CacheConstants.SETTLE_PACKAGE_KEY + note.getId(),
					note.getId(), CacheConstants.SETTLE_TIME, TimeUnit.DAYS);

			SysUser sysUser = sysUserMapper.selectById(note.getUserId());

			try {

				// 获取请求token
				String url = String.format(GIG_TOKEN_URL, upmsConfig.getGigServiceUrl());
				log.info("远端请求gig-token：{}", url);
				ResponseEntity<String> tokenResult = new RestTemplate().getForEntity(url, String.class,
						String.valueOf(operator.getDeptId()), "settle", String.valueOf(operator.getId()));
				log.warn("获取结算token：{}", tokenResult.getBody());
				if (!JSONUtil.isJson(tokenResult.getBody())) {
					return R.failed("获取结算token失败");
				}

				JSONObject jsonObject = JSONUtil.parseObj(tokenResult.getBody());

				if (jsonObject.getInt("code") != 0 || StrUtil.isBlank(jsonObject.getStr("data"))) {
					return R.failed("获取结算token失败");
				}

				String token = jsonObject.getStr("data");

				// 间隔100毫秒
				Thread.sleep(100);

				// 封装结算参数
				Map<String, Object> params = new HashMap<>();
				params.put("token", token);
				params.put("tenantId", operator.getDeptId());
				params.put("operatorId", operator.getId());
				params.put("requestId", RandomStringUtils.randomAlphabetic(12));
				params.put("taskName", wmScorePackage.getScorePackageName() + "_" + System.currentTimeMillis());
				params.put("amount", String.valueOf(note.getSettleAmount().doubleValue()));
				params.put("taskStartTime", wmScorePackage.getCreateTime().toLocalDate());
				params.put("taskEndTime", wmScorePackage.getUpdateTime().toLocalDate());
				params.put("taskLocation", "要易云");
				params.put("username", sysUser.getUsername());
				params.put("idCard", sysUser.getIdCardNumber());
				params.put("realName", sysUser.getRealname());
				params.put("bankCard", sysUser.getBankCardNumber());
				// 市场推广
				params.put("tagId", upmsConfig.getTagId());
				params.put("taskInvoiceContent", note.getCategoryName());
				params.put("endType", "CSO");
				params.put("enterpriseCode", taxCode);
				params.put("subjectType", "OLADING");
				params.put("subjectLocation", input.getSubjectLocation().getType());
				params.put("taskDescription", "根据要求，执行、并完成学术推广活动，并以在线平台工具采集、记录活动内容");
				params.put("acceptanceStandard", "完成不同任务获得不同任务积分，根据不同任务给与0~30000积分，每个积分兑换0.8~1.2元，按次数结算");


				if (SubjectLocation.JIN_YUAN.equals(input.getSubjectLocation())) {
					params.put("channel", "JIN_YUAN");
					params.put("taxMode", "GENERAL");
					params.put("transactionModel", "SUPERVISE");
				}
				// 海南飞亿 和 河南薪泰梓
				else {
					params.put("channel", SubjectLocation.FEI_YI.equals(input.getSubjectLocation()) ? "DEFAULT" : "XIN_TAI_ZI");
					params.put("taxMode", "SPECIAL");
					params.put("transactionModel", "CHANNEL");
				}

				// 发起结算
				String url1 = String.format(GIG_SETTLE_URL, upmsConfig.getGigServiceUrl());
				log.info("远端请求gig-settle：{}", url);
				HttpHeaders headers = new HttpHeaders();
				headers.setContentType(MediaType.APPLICATION_JSON);
				HttpEntity<String> result = new RestTemplate().exchange(url1, HttpMethod.POST, new HttpEntity<>(params, headers), String.class);
				log.warn("阿拉丁结算： {}", result.getBody());
				if (!JSONUtil.isJson(result.getBody())) {
					return R.failed("结算失败");
				}

				JSONObject settleObj = JSONUtil.parseObj(result.getBody());


				if (Objects.equals(settleObj.getInt("code"), CommonConstants.SUCCESS)) {
					log.info("自由职家结算提交成功： {}", note.getSettleNo());
					//streamId 获取不到
					if (StringUtils.isEmpty(settleObj.getStr("data"))) {
						log.warn("自由职家结算提交成功 requestId 获取不到： {}", note.getSettleNo());
						noticeInfo.append(sysUser.getRealname()).append("：提交结算成功，业务流水号获取不到，请联系管理员；");
					}
					note.setUpdateTime(LocalDateTime.now());
					note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
					// 新增字段streamId
					note.setStreamId(settleObj.getStr("data"));
					noticeInfo.append(sysUser.getRealname()).append("：提交结算成功；");
				} else {
					log.warn("自由职家结算提交失败： {}", note.getSettleNo());
					note.setUpdateTime(LocalDateTime.now());
					note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
					noticeInfo.append(sysUser.getRealname()).append("：结算提交失败-").append(settleObj.getStr("msg")).append("；");

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

				}
			} catch (Exception e) {
				log.warn("自由职家结算提交失败： {}", note.getSettleNo());
				note.setUpdateTime(LocalDateTime.now());
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
				noticeInfo.append(sysUser.getRealname()).append("：结算提交失败;");

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

		noteService.updateBatchById(notes);

		// 更新结算结果
		SettleNoteStatusOutput output = noteService.selectSettleNoteStatus(input.getId());
		WmScorePackage updateEntity = new WmScorePackage();
		updateEntity.setId(input.getId());
		updateEntity.setSettleStatus(output.toSettleStatus());
		wmScorePackageService.updateById(updateEntity);

		return R.ok(null, noticeInfo.toString());
	}

	/**
	 * 税邦云
	 *
	 * @param input      结算数据
	 * @param sysDeptSub 结算配置
	 * @param taxCode    税号
	 * @param operator   操作员
	 * @return 结果
	 */
	private R<?> settleByShuiBangYun(WmScorePackageSettleInput input,
									 SysDeptSub sysDeptSub,
									 String taxCode,
									 HnqzUser operator) {
		List<WmScorePackageSettleNote> notes = input.getNotes();
		StringBuilder noticeInfo = new StringBuilder();


		// WmScorePackageSettleNote
		for (WmScorePackageSettleNote note : notes) {
			note.setInvoiceType(input.getInvoiceCategory());
			note.setCategoryName(input.getCategoryName());
			note.setSubToGigTime(LocalDateTime.now());
		}
		noteService.updateBatchById(notes);


		for (WmScorePackageSettleNote note : notes) {
			SysUser sysUser = sysUserMapper.selectById(note.getUserId());

			SysUserSub userSub = sysUserSubMapper.selectOne(Wrappers.<SysUserSub>lambdaQuery()
					.eq(SysUserSub::getUserId, sysUser.getUserId())
					.eq(SysUserSub::getSubjectLocation, input.getSubjectLocation())
					.eq(SysUserSub::getDeptId, operator.getDeptId())
			);

			if (userSub == null) {
				log.info("结算对象-" + sysUser.getRealname() + "：认证信息不存在，不能结算");
				return R.failed("结算对象-" + sysUser.getRealname() + "：认证信息不存在，不能结算");
			}

			if (!Objects.equals(userSub.getCertStatus(), TaxHelperCertStatus.CERT.getCode())) {
				return R.failed(sysUser.getRealname() + "人员未认证或未绑卡，不能结算");
			}

			if (Boolean.TRUE.equals(redisTemplate.hasKey(CacheConstants.SETTLE_PACKAGE_KEY + note.getId()))) {
				return R.failed("结算对象-" + sysUser.getRealname() + "：正在结算，请勿重复结算");
			}

			if (DingEnum.NOTE_STATUS_SUCCESS.getType().equals(note.getSettleNoteStatus())) {
				log.info("结算对象-" + sysUser.getRealname() + "：已结算，请勿重复结算");
				return R.failed("结算对象-" + sysUser.getRealname() + "：已结算，请勿重复结算");
			}
			if (DingEnum.NOTE_STATUS_SUBMIT.getType().equals(note.getSettleNoteStatus())) {
				log.info("结算对象-" + sysUser.getRealname() + "：已提交，请等待耐心结算结果");
				return R.failed("结算对象-" + sysUser.getRealname() + "：已提交，请等待耐心结算结果");
			}

		}

		for (WmScorePackageSettleNote note : notes) {

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

			SysUser sysUser = sysUserMapper.selectById(note.getUserId());

			TaxHelperConfig config = new TaxHelperConfig();
			config.setAppId(sysDeptSub.getAppId());
			config.setAppSecrete(sysDeptSub.getAppSecret());
			config.setQueryUrl(sysDeptSub.getQueryUrl());

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

			taxHelperSettlementModel.setExtendFieldNames(Collections.singletonList("报告下载地址"));
			taxHelperSettlementModel.setCount(1);

			taxHelperSettlementModel.setNotifyUrl(String.format("%s/admin/taxhelper/%s/settlementNotify", taxNotifyConfig.getNotifyUrl(), sysUser.getUserId()));
			TaxHelperSettlementModel.DetailedArr detailedArr = new TaxHelperSettlementModel.DetailedArr();
			detailedArr.setIdCard(sysUser.getIdCardNumber());
			detailedArr.setInputAmount(note.getSettleAmount().doubleValue());
			detailedArr.setCategoryName(note.getCategoryName());
			taxHelperSettlementModel.setDetailedArr(Collections.singletonList(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(String.format("%s/#/h5/indexTask?id=%s&userId=%s", taxNotifyConfig.getTaskUrl(), note.getPackageId(), note.getUserId()));

			taxHelperSettlementModel.setAbstractArr(Collections.singletonList(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());
					noticeInfo.append(sysUser.getRealname()).append("：提交结算成功，业务流水号获取不到，请联系管理员；");
				}
				note.setUpdateTime(LocalDateTime.now());
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_SUBMIT.getType());
				// 新增字段streamId
				note.setStreamId(response.getMessage());
				noticeInfo.append(sysUser.getRealname()).append("：提交结算成功；");
			} else {
				log.info("税邦云结算提交失败： {}", note.getSettleNo());
				note.setUpdateTime(LocalDateTime.now());
				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
				noticeInfo.append(sysUser.getRealname()).append("：结算提交失败-").append(response.getMessage()).append("；");

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

			}
		}

		noteService.updateBatchById(notes);

		// 更新结算结果
		SettleNoteStatusOutput output = noteService.selectSettleNoteStatus(input.getId());
		WmScorePackage updateEntity = new WmScorePackage();
		updateEntity.setId(input.getId());
		updateEntity.setSettleStatus(output.toSettleStatus());
		wmScorePackageService.updateById(updateEntity);

		return R.ok(Boolean.TRUE, noticeInfo.toString());
	}

	/**
	 * 人力家结算
	 *
	 * @param input      结算数据
	 * @param sysDeptSub 结算配置
	 * @param operator   操作员
	 * @return 结果
	 */
	private R<?> settleByRenLiJia(WmScorePackageSettleInput input, SysDeptSub sysDeptSub, HnqzUser operator) {
		List<WmScorePackageSettleNote> notes = input.getNotes();

		for (WmScorePackageSettleNote note : notes) {
			note.setInvoiceType(input.getInvoiceCategory());
			note.setCategoryName(input.getCategoryName());
			note.setSubToGigTime(LocalDateTime.now());
		}
		noteService.updateBatchById(notes);

		log.info("结算包ID： {} 开始结算-----------", input.getId());
		log.info("结算渠道（税源地）： {} ", input.getSubjectLocation());

		DingConfig config = new DingConfig();
		config.setAppId(sysDeptSub.getAppId());
		config.setAppSecret(sysDeptSub.getAppSecret());
		config.setQueryUrl(sysDeptSub.getQueryUrl());

		for (WmScorePackageSettleNote note : notes) {

			SysUser sysUser = sysUserMapper.selectById(note.getUserId());
			SysUserSub userSub = sysUserSubMapper.selectOne(Wrappers.<SysUserSub>lambdaQuery()
					.eq(SysUserSub::getUserId, sysUser.getUserId())
					.eq(SysUserSub::getSubjectLocation, input.getSubjectLocation())
					.eq(SysUserSub::getDeptId, operator.getDeptId())
			);

			if (userSub == null) {
				log.info("结算对象-" + sysUser.getRealname() + "：认证信息不存在，不能结算");
				return R.failed("结算对象-" + sysUser.getRealname() + "：认证信息不存在，不能结算");
			}

			if (StringUtils.isEmpty(sysUser.getIdCardNumber())) {
				log.info("任务包众包代表-" + sysUser.getRealname() + "：身份证号未补录");
				// 添加登录提醒
				redisTemplate.opsForValue().set(CacheConstants.USER_NOTICE_KEY + sysUser.getUserId(), "1", CacheConstants.NOTICE_TIME, TimeUnit.DAYS);
				return R.failed("任务包众包代表-" + sysUser.getRealname() + "：身份证号未补录");
			}

			if (!DingEnum.CER_STATUS_1.getType().equals(userSub.getCertStatus())) {
				//认证中
				log.info("结算对象-" + sysUser.getRealname() + "：未认证成功，不能结算");
				return R.failed("结算对象-" + sysUser.getRealname() + "：未认证成功，不能结算");
			}

			if (Boolean.TRUE.equals(redisTemplate.hasKey(CacheConstants.SETTLE_PACKAGE_KEY + note.getId()))) {
				return R.failed("结算对象-" + sysUser.getRealname() + "：正在结算，请勿重复结算");
			}

			if (DingEnum.NOTE_STATUS_SUCCESS.getType().equals(note.getSettleNoteStatus())) {
				log.info("结算对象-" + sysUser.getRealname() + "：已结算，请勿重复结算");
				return R.failed("结算对象-" + sysUser.getRealname() + "：已结算，请勿重复结算");
			}
			if (DingEnum.NOTE_STATUS_SUBMIT.getType().equals(note.getSettleNoteStatus())) {
				log.info("结算对象-" + sysUser.getRealname() + "：已提交，请等待耐心结算结果");
				return R.failed("结算对象-" + sysUser.getRealname() + "：已提交，请等待耐心结算结果");
			}
		}

		// 进入结算环节  noticeInfo 失败原因
		StringBuilder noticeInfo = new StringBuilder();
		for (WmScorePackageSettleNote note : notes) {

			// 结算失败过的更新 settleNo
			if (DingEnum.NOTE_STATUS_FAIL.getType().equals(note.getSettleNoteStatus())) {
				note.setSettleNo(IdUtil.fastSimpleUUID());
			}

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

			SysUser sysUser = sysUserMapper.selectById(note.getUserId());

			// 校验认证信息
			if (DingEnum.CER_STATUS_1.getType().equals(sysUser.getRljCertStatus())) {
				//认证成功  发起结算
				//当前登陆人的机构名称
				String subjectName = sysDeptSub.getSubjectName();

				List<Map<String, String>> jsdList = new ArrayList<>(1);
				Map<String, String> jsdMap = new HashMap<>(4);
				jsdMap.put("amount", String.format("%.2f", note.getSettleAmount().doubleValue()));
				jsdMap.put("mobile", sysUser.getPhone());
				jsdMap.put("idCard", sysUser.getIdCardNumber());
				jsdMap.put("name", sysUser.getRealname());
				jsdList.add(jsdMap);

				EmployPayResponse employPayResponse = dingService.payV2(config, subjectName,
						note.getSettleNo(), input.getScorePackageName(),
						input.getInvoiceCategory(), jsdList);

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

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

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

						savePayoffFormNote(note);

					}

					//结算提交失败的数据
					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() + "；");
						noticeInfo.append("结算对象-").append(sysUser.getRealname()).append("，结算失败：").append(failResult.get(0).getCheckRemark()).append("；");
						note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
					}
				}

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

				note.setSettleNoteStatus(DingEnum.NOTE_STATUS_FAIL.getType());
			}

		}

		noteService.updateBatchById(notes);

		// 更新结算结果
		SettleNoteStatusOutput output = noteService.selectSettleNoteStatus(input.getId());
		WmScorePackage updateEntity = new WmScorePackage();
		updateEntity.setId(input.getId());
		updateEntity.setSettleStatus(output.toSettleStatus());
		wmScorePackageService.updateById(updateEntity);

		return R.ok(Boolean.TRUE, noticeInfo.toString());
	}

	/**
	 * 提交成功的记录
	 *
	 * @param note 结算记录
	 */
	private void savePayoffFormNote(WmScorePackageSettleNote note) {
		WmPayOff wmPayOff = new WmPayOff();
		wmPayOff.setScoreId(note.getPackageId());
		wmPayOff.setNoteId(String.valueOf(note.getId()));
		wmPayOff.setStatementNo(note.getSettleNo());
		wmPayOff.setSettleAmount(note.getSettleAmount());
		wmPayOff.setSettlePeople(note.getUserId());

		this.save(wmPayOff);
	}

}
