package com.izouma.nineth.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.io.file.PathUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.izouma.nineth.config.GeneralProperties;
import com.izouma.nineth.config.LianlianpayProperties;
import com.izouma.nineth.config.SysConstants;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.dto.pay.PayResult;
import com.izouma.nineth.dto.pay.RechargeResult;
import com.izouma.nineth.dto.pay.WithdrawResult;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.service.pay.PayHelper;
import com.izouma.nineth.utils.IPUtils;
import com.izouma.nineth.utils.ImageUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import com.izouma.nineth.utils.lianlianpay.LianlianpayClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
@AllArgsConstructor
@Slf4j
public class LianlianPayService {

    private LianlianpayProperties lianlianpayProperties;

    private LianlianpayClient lianlianpayClient;

    private UserRepo userRepo;

    private IdentityAuthRepo identityAuthRepo;

    private UserBankCardRepo userBankCardRepo;

    private UserFundAccountRepo userFundAccountRepo;

    private SnowflakeIdWorker snowflakeIdWorker;

    private PayHelper payHelper;

    private DivMoneyRepo divMoneyRepo;

    private PaymentInfoRepo paymentInfoRepo;

    private UserAddressRepo userAddressRepo;

    private GeneralProperties generalProperties;

    private SysConfigService sysConfigService;


    /**
     * 获取用户账号
     *
     * @param userId
     * @return
     */
    private String getBizUserId(Long userId) {
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
        //会员ID
        if(StringUtils.isEmpty(user.getMemberId())){
            String memberPrefix  = sysConfigService.getStringDefault(SysConstants.MEMBER_PREFIX);
            //多平台唯一编号
            String memberId = memberPrefix + user.getId().toString() + "_" + user.getPhone();
            user.setMemberId(memberId);
            userRepo.save(user);
        }
        return user.getMemberId();
    }


    /**
     * 获取用户账号
     *
     * @param userId
     * @return
     */
    private User getUser(Long userId) {
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
        return user;
    }

    /**
     * 获取风控参数
     * @param goodsName
     * @return
     */
    public JSONObject getRiskItem(Long userId, String goodsName){
        String bizUserId = getBizUserId(userId);
        User user = getUser(userId);
        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(userId, AuthStatus.SUCCESS)
                .orElseThrow(new BusinessException("用户未通过实名认证，无法获取风控信息"));
        String registerDt = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(user.getCreatedAt());
        JSONObject riskItem = new JSONObject();
        //>>>>>>基础类风控参数
        riskItem.put("frms_ware_category", "4007");//工艺美术品及收藏品零售
        riskItem.put("user_info_mercht_userno", bizUserId);
        riskItem.put("user_info_bind_phone", user.getPhone());
        riskItem.put("user_info_dt_register", registerDt);
        riskItem.put("goods_name", goodsName);

        //>>>>>>API调用必传参数
        // 0 - 商户代扣模式
        //10 - APP。
        //13 - PC。
        //16 - H5。
        //18 - IVR。
        riskItem.put("frms_client_chnl", "16");
        //用户交易请求IP，frms_client_chnl=0可不传。
        riskItem.put("frms_ip_addr", IPUtils.getIpAddr());
        //该字段指开通API的商户，用户有无勾选连连支付服务协议。（商户接入微信扫码支付时，该字段无需传输）
        riskItem.put("user_auth_flag", "1");
        //riskItem.put("repay_auth_flag", "1");//代收授权标记,可选

        //>>>>>>实名类参数
        riskItem.put("user_info_full_name", identityAuth.getRealName());
        riskItem.put("user_info_id_type", "0");//身份证
        riskItem.put("user_info_id_no", identityAuth.getIdNo());//证件编码
        riskItem.put("user_info_identify_state", "1");//是否有实名认证
        //实名认证方式。
        //1 - 银行卡认证。
        //2 - 现场认证。
        //3 - 身份证远程认证。
        //4 - 其他认证。
        riskItem.put("user_info_identify_type", "1");
        return riskItem;

    }

    /**
     * 解析结果内容
     *
     * @param wrappedData
     * @return
     */
    public JSONObject checkSuccessBody(String wrappedData, String fromSign) {
        JSONObject resBodyJson = null;
        try {

            lianlianpayClient.verifySign(wrappedData, fromSign);

            resBodyJson = lianlianpayClient.checkSuccessBody(wrappedData, false);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException("签名校验错误", e);
        }
        return resBodyJson;
    }


    /**
     * 开户短信申请
     *
     * @param userId
     * @return
     */
    public JSONObject registerVerifyCodeApply(Long userId, String phone) {
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("reg_phone", phone);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/regphone-verifycode-apply", param);
        return res;
    }

    /**
     * 开户短信验证
     *
     * @param userId
     * @param verifyCode
     * @return
     */
    public JSONObject registerVerifyCodeVerify(Long userId, String verifyCode) {
        String bizUserId = getBizUserId(userId);
        User user = getUser(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("reg_phone", user.getPhone());
        param.put("verify_code", verifyCode);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/regphone-verifycode-verify", param);
        return res;
    }


    /**
     * 上传文件
     * @param url
     * @return
     */
    public JSONObject uploadFile(Long userId, String url){
        String txnseqno = String.valueOf(snowflakeIdWorker.nextId());
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        String bizUserId = getBizUserId(userId);

        String path = URLUtil.getPath(url);
        //文件类型。支持bmp、png、jpeg、jpg、gif。
        String fileType = FileNameUtil.getSuffix(path);
        if(StringUtils.isEmpty(fileType)){
            fileType = "jpg";
        }
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("txn_seqno",txnseqno );
        param.put("txn_time", txnTime );
        param.put("file_type", fileType );
        param.put("context_type", "USER_IMAGE" );//影像文件
        param.put("file_name", FileNameUtil.getName(path));
        byte[] data;
        try {
            data = IOUtils.toByteArray(new URL(url));
        } catch (IOException e) {
            throw new RuntimeException("读取资源失败:" +  url, e);
        }

        String fileData = Base64.encodeBase64String(data);
        param.put("file_context", fileData);
        JSONObject res = lianlianpayClient.postJson(lianlianpayProperties.getFileGateWay() + "/v1/documents/upload", param);
        return res;
    }


    /**
     * 注册申请
     *
     * @param identityAuth
     * @return
     */
    public JSONObject registerApply(IdentityAuth identityAuth, UserBankCard userBankCard) {
        String bizUserId = getBizUserId(userBankCard.getUserId());
        User user = getUser(userBankCard.getUserId());
        String txnseqno = String.valueOf(snowflakeIdWorker.nextId());
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        String notifyUrl = payHelper.resolveLianlianAccountNotifyUrl(txnseqno);

        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("txn_seqno", txnseqno);//商户系统唯一交易流水号。由商户自定义。
        param.put("txn_time", txnTime);//商户系统交易时间,格式：yyyyMMddHHmmss。
        param.put("notify_url", notifyUrl);
//        param.put("open_sms_flag", "N");//开户成功短信通知,暂只满足富民银行
        //param.put("risk_item", "");

        JSONObject basicInfo = new JSONObject();
        basicInfo.put("reg_phone", user.getPhone());
        basicInfo.put("user_name", userBankCard.getRealName());
        basicInfo.put("id_type", "ID_CARD");
        basicInfo.put("id_no", userBankCard.getIdNo());
        //api操作必须
        if (identityAuth.getIdEndDate() == null) {
            throw new BusinessException("缺失证件失效日期");
        }
        String idExp = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdEndDate());
        basicInfo.put("id_exp", idExp);

        //非必选项
        if (identityAuth.getIdStartDate() != null) {
            String idStd = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdStartDate());
            basicInfo.put("id_std", idStd);
        }

        //basicInfo.put("id_authority", "");
        //basicInfo.put("area_code", "");
        //basicInfo.put("address", "");
        basicInfo.put("occupation", "19");//职业：其他

        if(StringUtils.isNotEmpty(identityAuth.getIdFront())){
            //人面像
            String docId = uploadFile(userBankCard.getUserId(),
                    identityAuth.getIdFront()).getString("doc_id");
            basicInfo.put("id_portrait", docId);
        }
        if(StringUtils.isNotEmpty(identityAuth.getIdBack())){
            //国徽像
            String docId = uploadFile(userBankCard.getUserId(),
                    identityAuth.getIdBack()).getString("doc_id");
            basicInfo.put("id_emblem", docId);
        }



        param.put("basicInfo", basicInfo);

        JSONObject linkedAcctInfo = new JSONObject();
        linkedAcctInfo.put("linked_acctno", userBankCard.getBankNo());
        linkedAcctInfo.put("linked_phone", userBankCard.getPhone());
        param.put("linkedAcctInfo", linkedAcctInfo);


        JSONObject accountInfo = new JSONObject();
        //ACCOUNT_BOOK	账簿
        //PERSONAL_PAYMENT_ACCOUNT	个人支付账户
        //ENTERPRISE_PAYMENT_ACCOUNT	企业支付账户
        //MAX	超级用户
        accountInfo.put("account_type", "PERSONAL_PAYMENT_ACCOUNT");
        accountInfo.put("account_need_level", "V2");

        param.put("accountInfo", accountInfo);

        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/openacct-apply-individual", param);
        return res;
    }

    /**
     * 使用页面开户
     * @param identityAuth
     * @param userBankCard
     * @return
     */
    public JSONObject registerApplyWithPage(IdentityAuth identityAuth, UserBankCard userBankCard, String returnUrl){
        String bizUserId = getBizUserId(userBankCard.getUserId());
        User user = getUser(userBankCard.getUserId());
        String txnseqno = String.valueOf(snowflakeIdWorker.nextId());
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        String notifyUrl = payHelper.resolveLianlianAccountNotifyUrl(txnseqno);

        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("txn_seqno", txnseqno);//商户系统唯一交易流水号。由商户自定义。
        param.put("txn_time", txnTime);//商户系统交易时间,格式：yyyyMMddHHmmss。
        param.put("flag_chnl", "H5");//应用渠道
        param.put("notify_url", notifyUrl);
        param.put("return_url", returnUrl);//前端返回地址
        //INNERUSER：个人用户
        //INNERCOMPANY：企业用户
        param.put("user_type", "INNERUSER");//开户类型


        JSONObject basicInfo = new JSONObject();
        basicInfo.put("reg_phone", user.getPhone());
        basicInfo.put("user_name", userBankCard.getRealName());
        basicInfo.put("id_type", "ID_CARD");
        basicInfo.put("id_no", userBankCard.getIdNo());

        //页面交易可选
        if (identityAuth.getIdEndDate() != null) {
            String idExp = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdEndDate());
            basicInfo.put("id_exp", idExp);
        }


        //非必选项
        if (identityAuth.getIdStartDate() != null) {
            String idStd = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdStartDate());
            basicInfo.put("id_std", idStd);
        }

        //basicInfo.put("reg_email", "");
        List<UserAddress> userAddressList = userAddressRepo.findByUserIdAndDelFalse(user.getId());
        if(userAddressList.size() > 0){
            //使用用户地址
            UserAddress userAddress = userAddressList.get(0);
            if(userAddress != null){
                String  fullAddress = userAddress.getProvinceName() + userAddress.getCityName()
                        + userAddress.getDistrictName() + userAddress.getAddress();
                basicInfo.put("address", fullAddress);
            }
        }

        basicInfo.put("occupation", "19");//职业：其他

        param.put("basicInfo", basicInfo);

        //开户绑卡
        JSONObject linkedAcctInfo = new JSONObject();
        linkedAcctInfo.put("linked_acctno", userBankCard.getBankNo());
        linkedAcctInfo.put("linked_phone", userBankCard.getPhone());
        param.put("linkedAcctInfo", linkedAcctInfo);

        //开户账户申请信息
        JSONObject accountInfo = new JSONObject();
        //ACCOUNT_BOOK	账簿
        //PERSONAL_PAYMENT_ACCOUNT	个人支付账户
        //ENTERPRISE_PAYMENT_ACCOUNT	企业支付账户
        //MAX	超级用户
        accountInfo.put("account_type", "PERSONAL_PAYMENT_ACCOUNT");
        accountInfo.put("account_need_level", "V2");

        param.put("accountInfo", accountInfo);

        //指定固定地址
        JSONObject res = lianlianpayClient.postJson("https://accpgw.lianlianpay.com/v1/acctmgr/openacct-apply", param);
        return res;

    }

    /**
     * 获取随机因子
     *
     * @param userId
     * @return
     */
    public JSONObject getRandom(Long userId, String algorithm) {
        JSONObject param = new JSONObject();
        String bizUserId = getBizUserId(userId);
        param.put("user_id", bizUserId);
        //交易发起渠道。
        //ANDROID
        //IOS
        //H5
        //PC
        param.put("flag_chnl", "H5");
        //APP包名。flag_chnl为H5时，送商户一级域名
        param.put("pkg_name", generalProperties.getHost());
        //APP应用名。flag_chnl为H5时，送商户一级域名
        param.put("app_name", generalProperties.getHost());
//        param.put("pkg_name", "test");
//        param.put("app_name", "test");
        //加密算法。
        //RSA：国际通用RSA算法
        //SM2 ：国密算法
        //默认 RSA算法
        if(StringUtils.isNotEmpty(algorithm)){
            param.put("encrypt_algorithm", algorithm);
        }

        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/get-random", param);
        return res;
    }

    /**
     * 注册校验，设置支付密码
     *
     * @return
     */
    public JSONObject registerVerify(UserFundAccount lianlianAccount, String password, String randomKey, String verifyCode) {
        String bizUserId = getBizUserId(lianlianAccount.getUserId());
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("txn_seqno", lianlianAccount.getOrderNo());
        param.put("token", lianlianAccount.getToken());
        param.put("verify_code", verifyCode);
        //6-12位的字母、数字，不可以是连续或者重复的数字和字母，正则：^[a-zA-Z0-9]{6,12}$
        param.put("password", password);
        param.put("random_key", randomKey);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/openacct-verify-individual", param);
        return res;

    }


    /**
     * 绑卡申请
     *
     * @return
     */
    public JSONObject bindCardApply(Long userId, String bankNo, String phone,String password, String randomKey) {
        String bizUserId = getBizUserId(userId);
        String txnseqno = String.valueOf(snowflakeIdWorker.nextId());

        String notifyUrl = payHelper.resolveBindCardNotify(txnseqno);
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("txn_seqno", txnseqno);
        param.put("txn_time", txnTime);
        param.put("notify_url", notifyUrl);
        //param.put("risk_item", "");
        param.put("linked_acctno", bankNo);
        param.put("linked_phone", phone);
        param.put("password", password);

        param.put("random_key", randomKey);

        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/individual-bindcard-apply", param);
        return res;
    }

    /**
     * 绑卡校验
     *
     * @param userId
     * @param token
     * @param verifyCode
     * @return
     */
    public JSONObject bindCardVerify(Long userId, String bindOrderNo, String token, String verifyCode) {
        String bizUserId = getBizUserId(userId);

        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("txn_seqno", bindOrderNo);
        param.put("token", token);
        param.put("verify_code", verifyCode);

        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/individual-bindcard-verify", param);
        return res;
    }

    /**
     * 绑卡查询
     *
     * @param userId
     * @return
     */
    public JSONObject bindCardQuery(Long userId) {
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/query-linkedacct", param);
        return res;
    }


    /**
     * 解绑卡申请
     * @return
     */
    public JSONObject unbindCardApply(UserBankCard userBankCard, String password, String randomKey){
        String bizUserId = getBizUserId(userBankCard.getUserId());
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("txn_seqno", userBankCard.getUnbindOrderNo() );
        param.put("txn_time", txnTime);
        String notifyUrl = payHelper.resolveBindCardNotify(userBankCard.getUnbindOrderNo());
        param.put("notify_url", notifyUrl);
        param.put("linked_acctno", userBankCard.getBankNo());
        param.put("password", password);
        param.put("random_key", randomKey);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/unlinkedacct-ind-apply", param);
        return res;
    }

    /**
     * 用户信息查询
     *
     * @param userId
     * @return
     */
    public JSONObject userInfoQuery(Long userId) {
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/query-userinfo", param);

        return res;
    }


    /**
     * 修改密码
     * @param userId
     * @param password
     * @param randomKey
     * @param passwordNew
     * @param riskItem
     * @return
     */
    public JSONObject changePassword(Long userId, String password, String randomKey, String passwordNew, JSONObject riskItem){
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("risk_item", riskItem.toJSONString());
        param.put("password", password);
        param.put("random_key", randomKey);
        param.put("password_new", passwordNew);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/change-password", param);

        return res;
    }

    /**
     * 找回密码申请
     * @return
     */
    public JSONObject findPasswordApply(Long userId, String bankNo, JSONObject riskItem){
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("linked_acctno", bankNo);
        param.put("risk_item", riskItem.toJSONString());
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/find-password-apply", param);

        return res;
    }

    /**
     * 找回密码校验
     * @param userId
     * @param token
     * @param verifyCode
     * @param password
     * @param randomKey
     * @return
     */
    public JSONObject findPasswordVerify(Long userId, String token, String verifyCode, String password, String randomKey){
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("token", token);
        param.put("verify_code", verifyCode);
        param.put("password", password);
        param.put("random_key", randomKey);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/find-password-verify", param);

        return res;
    }

    /**
     * 支付密码校验
     * @param userId
     * @param password
     * @param randomKey
     * @return
     */
    public JSONObject passwordVerify(Long userId, String password, String randomKey){
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("password", password);
        param.put("random_key", randomKey);
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/validate-password", param);

        return res;
    }

    /**
     * 账户信息查询
     * @param userId
     * @return
     */
    public JSONObject accountInfoQuery(Long userId){
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("user_type", "INNERUSER");
        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/query-acctinfo", param);

        return res;

    }


    /**
     * 账户下单
     *
     * @param paymentInfo
     * @return
     */
    public JSONObject payCreate(PaymentInfo paymentInfo, List<DivMoney> divMoneyList, boolean hasWallet) {

        String bizUserId = getBizUserId(paymentInfo.getUserId());

        JSONObject bodyJson = new JSONObject();
        //交易类型
        //用户充值：USER_TOPUP
        //商户充值：MCH_TOPUP
        //普通消费：GENERAL_CONSUME
        //担保消费：SECURED_CONSUME
        bodyJson.put("txn_type", "GENERAL_CONSUME");
        bodyJson.put("user_id", bizUserId);
        // 注册用户：REGISTERED
        // 匿名用户：ANONYMOUS
        if(hasWallet && paymentInfo.getPayMethod() == PayMethod.WALLET ){
            bodyJson.put("user_type", "REGISTERED");
        }else{
            bodyJson.put("user_type", "ANONYMOUS");
        }


        String returnUrl = payHelper.resolveReturnUrl(paymentInfo);
        bodyJson.put("notify_url", paymentInfo.getNotifyUrl());
        bodyJson.put("return_url", returnUrl);
        //默认3天,建议:最短失效时间间隔大于5分钟。
        int payExpire = payHelper.getExpireInterval() - 1;
        bodyJson.put("pay_expire", payExpire);


        //订单信息
        JSONObject orderInfo = new JSONObject();
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        orderInfo.put("txn_seqno", paymentInfo.getOrderNo());
        orderInfo.put("txn_time", txnTime);
        orderInfo.put("total_amount", paymentInfo.getPayAmt());
        //orderInfo.put("fee_amount", 0);//手续费
        orderInfo.put("order_info", paymentInfo.getGoodsTitle());
        orderInfo.put("goods_name", paymentInfo.getGoodsTitle());
        //orderInfo.put("goods_url", "");

        bodyJson.put("orderInfo", orderInfo);

        //GENERAL_CONSUME：必须上送收款方，且不可更改
        //收款方,分账
        JSONArray payeeInfo = new JSONArray();
        if(divMoneyList != null && !divMoneyList.isEmpty()){
            divMoneyList.forEach((item) -> {
                JSONObject receive = new JSONObject();
                //收款方标识，收款方为用户时，为用户user_id，收款方为平台商户时，取平台商户号。
                if (item.getUserId() != null) {
                    receive.put("payee_id", item.getMemberId());
                    receive.put("payee_type", "USER");
                    receive.put("payee_accttype", "USEROWN");
                    receive.put("payee_amount", item.getAmount());
                    receive.put("payee_memo", "用户分润费");
                } else {
                    receive.put("payee_id", lianlianpayProperties.getMid());
                    receive.put("payee_type", "MERCHANT");
                    receive.put("payee_accttype", "MCHOWN");
                    receive.put("payee_amount", item.getAmount());
                    receive.put("payee_memo", "平台分润费");
                }

                payeeInfo.add(receive);
            });
        }else{
            JSONObject receive = new JSONObject();
            receive.put("payee_id", lianlianpayProperties.getMid());
            receive.put("payee_type", "MERCHANT");
            receive.put("payee_amount", paymentInfo.getPayAmt());
            receive.put("payee_memo", "平台分润费");
            payeeInfo.add(receive);
        }


        bodyJson.put("payeeInfo", payeeInfo);

        JSONObject res = lianlianpayClient.postJson("/v1/txn/tradecreate", bodyJson);

        return res;
    }

    /**
     * 续费下单
     *
     * @param walletRenewOrder
     * @return
     */
    public JSONObject payCreate(WalletRenewOrder walletRenewOrder, boolean hasWallet) {

        String bizUserId = getBizUserId(walletRenewOrder.getUserId());

        JSONObject bodyJson = new JSONObject();
        //交易类型
        //用户充值：USER_TOPUP
        //商户充值：MCH_TOPUP
        //普通消费：GENERAL_CONSUME
        //担保消费：SECURED_CONSUME
        bodyJson.put("txn_type", "GENERAL_CONSUME");
        bodyJson.put("user_id", bizUserId);
        // 注册用户：REGISTERED
        // 匿名用户：ANONYMOUS
        if(hasWallet  && walletRenewOrder.getPayMethod() == PayMethod.WALLET ){
            bodyJson.put("user_type", "REGISTERED");
        }else{
            bodyJson.put("user_type", "ANONYMOUS");
        }

        String returnUrl = payHelper.resolveHome(0);
        bodyJson.put("notify_url", walletRenewOrder.getNotifyUrl());
        bodyJson.put("return_url", returnUrl);
        //默认3天,建议:最短失效时间间隔大于5分钟。
        int payExpire = payHelper.getExpireInterval() - 1;
        bodyJson.put("pay_expire", payExpire);


        //订单信息
        JSONObject orderInfo = new JSONObject();
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        orderInfo.put("txn_seqno", walletRenewOrder.getOrderNo());
        orderInfo.put("txn_time", txnTime);
        orderInfo.put("total_amount", walletRenewOrder.getPayAmt());
        //orderInfo.put("fee_amount", 0);//手续费
        orderInfo.put("order_info", walletRenewOrder.getGoodsTitle());
        orderInfo.put("goods_name", walletRenewOrder.getGoodsTitle());
        //orderInfo.put("goods_url", "");

        bodyJson.put("orderInfo", orderInfo);

        //GENERAL_CONSUME：必须上送收款方，且不可更改
        //收款方,分账
        JSONArray payeeInfo = new JSONArray();
        JSONObject receive = new JSONObject();
        receive.put("payee_id", lianlianpayProperties.getMid());
        receive.put("payee_type", "MERCHANT");
        receive.put("payee_amount", walletRenewOrder.getPayAmt());
        receive.put("payee_memo", "平台分润费");
        payeeInfo.add(receive);

        bodyJson.put("payeeInfo", payeeInfo);

        JSONObject res = lianlianpayClient.postJson("/v1/txn/tradecreate", bodyJson);

        return res;
    }


    /**
     *
     * 交易退款
     *
     */
    public JSONObject accountPayRefund(PaymentInfo paymentInfo, String refundReason) {
        String orderCode = String.valueOf(snowflakeIdWorker.nextId());
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        String notifyUrl = payHelper.resolveRefundNotifyUrl(paymentInfo.getOrderNo());
        JSONObject bodyJson = new JSONObject();

        String bizUserId = getBizUserId(paymentInfo.getUserId());

        bodyJson.put("user_id", bizUserId);
        bodyJson.put("notify_url", notifyUrl);
        bodyJson.put("refund_reason", refundReason);


        JSONObject originalOrderInfo = new JSONObject();
        originalOrderInfo.put("txn_seqno", paymentInfo.getOrderNo());
        originalOrderInfo.put("total_amount", paymentInfo.getPayAmt());

        bodyJson.put("originalOrderInfo", originalOrderInfo);

        JSONObject refundOrderInfo = new JSONObject();
        refundOrderInfo.put("refund_seqno",orderCode);
        //refundOrderInfo.put("order_info","");
        refundOrderInfo.put("refund_time", txnTime);
        refundOrderInfo.put("refund_amount", paymentInfo.getPayAmt());

        bodyJson.put("refundOrderInfo", refundOrderInfo);

        //原收款方信息
        JSONArray pyeeRefundInfos = new JSONArray();
        List<DivMoney> divMoneyList = divMoneyRepo.findByOrderId(paymentInfo.getOrderId());
        if(divMoneyList != null && !divMoneyList.isEmpty()){
            divMoneyList.forEach((item) -> {
                JSONObject receive = new JSONObject();
                //收款方标识，收款方为用户时，为用户user_id，收款方为平台商户时，取平台商户号。
                if (item.getUserId() != null) {
                    receive.put("payee_id", item.getMemberId());
                    receive.put("payee_type", "USER");
                    receive.put("payee_accttype", "USEROWN");
                    receive.put("payee_refund_amount", item.getAmount());
                } else {
                    receive.put("payee_id", lianlianpayProperties.getMid());
                    receive.put("payee_type", "MERCHANT");
                    receive.put("payee_accttype", "MCHOWN");
                    receive.put("payee_refund_amount", item.getAmount());
                }

                pyeeRefundInfos.add(receive);
            });
        }else{
            JSONObject receive = new JSONObject();
            receive.put("payee_id", lianlianpayProperties.getMid());
            receive.put("payee_type", "MERCHANT");
            receive.put("payee_accttype", "MCHOWN");
            receive.put("payee_refund_amount", paymentInfo.getPayAmt());
            pyeeRefundInfos.add(receive);
        }

        bodyJson.put("pyeeRefundInfos", pyeeRefundInfos);


        JSONArray refundMethods = new JSONArray();
        JSONObject methodObj = new JSONObject();
        if(paymentInfo.getPayMethod() == PayMethod.BANK){
            methodObj.put("method", "AGRT_DEBIT_CARD");
        }else{
            methodObj.put("method", "BALANCE");
        }

        methodObj.put("amount", paymentInfo.getPayAmt());
        refundMethods.add(methodObj);

        bodyJson.put("refundMethods", refundMethods);

        JSONObject res = lianlianpayClient.postJson("/v1/txn/more-payee-refund", bodyJson);

        return res;

    }



    /**
     * 账户充值
     * @return
     */
    public JSONObject recharge(RechargeOrder rechargeOrder){
        String bizUserId = getBizUserId(rechargeOrder.getUserId());
        JSONObject bodyJson = new JSONObject();
        //交易类型
        //用户充值：USER_TOPUP
        //商户充值：MCH_TOPUP
        //普通消费：GENERAL_CONSUME
        //担保消费：SECURED_CONSUME
        bodyJson.put("txn_type", "USER_TOPUP");
        bodyJson.put("user_id", bizUserId);
        // 注册用户：REGISTERED
        // 匿名用户：ANONYMOUS
        bodyJson.put("user_type", "REGISTERED");

        bodyJson.put("notify_url", rechargeOrder.getNotifyUrl());
        bodyJson.put("return_url", rechargeOrder.getFrontUrl());
        //默认3天,建议:最短失效时间间隔大于5分钟。
        bodyJson.put("pay_expire", 30);//固定30分钟

        //订单信息
        JSONObject orderInfo = new JSONObject();
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        orderInfo.put("txn_seqno", rechargeOrder.getOrderNo());
        orderInfo.put("txn_time", txnTime);
        orderInfo.put("total_amount", rechargeOrder.getOrderAmount());
        if(rechargeOrder.getUserFeeAmt() != null){
            orderInfo.put("fee_amount", rechargeOrder.getUserFeeAmt());//收取用户的手续费
        }
        orderInfo.put("order_info", rechargeOrder.getTitle());
        orderInfo.put("goods_name", rechargeOrder.getTitle());
        //orderInfo.put("goods_url", "");

        bodyJson.put("orderInfo", orderInfo);

        JSONObject res = lianlianpayClient.postJson("/v1/txn/tradecreate", bodyJson);

        return res;

    }

    /**
     * 提现申请
     * @return
     */
    public JSONObject withdrawApply(WithdrawApply withdrawApply, String password,
                                    String randomKey, JSONObject riskItem){
        String bizUserId = getBizUserId(withdrawApply.getUserId());
        JSONObject bodyJson = new JSONObject();

        bodyJson.put("notify_url", withdrawApply.getNotifyUrl());
        //默认3天,建议:最短失效时间间隔大于5分钟。
        bodyJson.put("pay_expire", 30);//固定30分钟

        //风控参数
        bodyJson.put("risk_item", riskItem.toJSONString());

        if(StringUtils.isNotEmpty(withdrawApply.getRelatedCardNo())){
            //使用绑卡协议
            bodyJson.put("linked_agrtno", withdrawApply.getRelatedCardNo());
        }else{
            //指定银行卡号
            bodyJson.put("linked_acctno", withdrawApply.getBankNo());
        }


        //Y：支持垫资
        //N：不支持垫资
        bodyJson.put("funds_flag", "N");
        //是否审核
        bodyJson.put("check_flag", "N");
        //到账类型。
        //TRANS_THIS_TIME :实时到账
        //TRANS_NORMAL :普通到账（2小时内）
        //TRANS_NEXT_TIME :次日到账
        //默认：实时到账。
        bodyJson.put("pay_time_type", "TRANS_THIS_TIME");

        //订单信息
        JSONObject orderInfo = new JSONObject();
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        orderInfo.put("txn_seqno", withdrawApply.getOrderNo());
        orderInfo.put("txn_time", txnTime);
        orderInfo.put("total_amount", withdrawApply.getOrderAmount());
        orderInfo.put("fee_amount", withdrawApply.getUserFeeAmt());//收取用户的手续费
        orderInfo.put("order_info", withdrawApply.getTitle());

        //单笔金额大于等于5w必须提供
        orderInfo.put("postscript", withdrawApply.getTitle());//附言

        bodyJson.put("orderInfo", orderInfo);


        JSONObject payerInfo = new JSONObject();
        //用户：USER
        //平台商户：MERCHANT
        payerInfo.put("payer_type", "USER");
        payerInfo.put("payer_id", bizUserId);
        payerInfo.put("payer_accttype", "USEROWN");
        payerInfo.put("password", password);//用户提现时必须
        payerInfo.put("random_key", randomKey);//用户提现时必须
        //payerInfo.put("pap_agree_no", "");

        bodyJson.put("payerInfo", payerInfo);

        JSONObject res = lianlianpayClient.postJson("/v1/txn/withdrawal", bodyJson);

        return res;


    }


    /**
     * 余额支付
     * @param orderNo 订单编号
     * @param totalAmount  金额
     * @param password 密码
     * @param randomKey 随机因子
     * @return
     */
    public JSONObject paymentBalance(UserFundAccount lianlianAccount, String orderNo, BigDecimal totalAmount
            , String password, String randomKey, JSONObject riskItem){
        String bizUserId = getBizUserId(lianlianAccount.getUserId());
        JSONObject param = new JSONObject();
        param.put("txn_seqno", orderNo);
        param.put("total_amount", totalAmount);
        //param.put("coupon_amount", "");//优惠金额
        //param.put("directionalpay_flag", "N");//定向支付
        param.put("risk_item", riskItem.toJSONString());

        JSONObject payerInfo = new JSONObject();
        payerInfo.put("user_id", bizUserId);
        //支付密码可选
        if(StringUtils.isNotEmpty(password)){
            payerInfo.put("password", password);
            payerInfo.put("random_key", randomKey);
        }


        param.put("payerInfo", payerInfo);

        JSONObject res = lianlianpayClient.postJson("/v1/txn/payment-balance", param);
        return res;

    }


    /**
     * 快捷支付
     * @param orderNo
     * @param totalAmount
     * @param password
     * @param randomKey
     * @param riskItem
     * @return
     */
    public JSONObject paymentQuickpay(UserBankCard userBankCard, String orderNo, BigDecimal totalAmount
            ,String password, String randomKey, JSONObject riskItem){
        String bizUserId = getBizUserId(userBankCard.getUserId());

        JSONObject param = new JSONObject();
        param.put("txn_seqno", orderNo);
        param.put("total_amount", totalAmount);
        //param.put("coupon_amount", "");//优惠金额
        //param.put("directionalpay_flag", "N");//定向支付
        param.put("risk_item", riskItem.toJSONString());

        JSONObject payerInfo = new JSONObject();
        payerInfo.put("user_id", bizUserId);
        //支付密码可选
        if(StringUtils.isNotEmpty(password)){
            payerInfo.put("password", password);
            payerInfo.put("random_key", randomKey);
        }

        param.put("payerInfo", payerInfo);

        //快捷支付银行信息
        JSONObject bankCardInfo  = new JSONObject();
        if(StringUtils.isNotEmpty(userBankCard.getThirdBankId())){
            bankCardInfo.put("linked_agrtno", userBankCard.getThirdBankId());//协议
        }else{
            //首次
            bankCardInfo.put("linked_acctno", userBankCard.getBankNo());
            bankCardInfo.put("linked_phone", userBankCard.getPhone());//银行预留手机号
            bankCardInfo.put("linked_acctname", userBankCard.getRealName());
            bankCardInfo.put("id_type", "ID_CARD");
            bankCardInfo.put("id_no", userBankCard.getIdNo());
        }

        param.put("bankCardInfo", bankCardInfo);

        //支付方式
        JSONArray payMethods  = new JSONArray();
        JSONObject methodObj = new JSONObject();
        //余额 :BALANCE
        //优惠券 :COUPON
        //协议支付借记卡 :AGRT_DEBIT_CARD
        //协议支付信用卡 :AGRT_CREDIT_CARD
        methodObj.put("method", "AGRT_DEBIT_CARD");
        methodObj.put("amount", totalAmount);
        payMethods.add(methodObj);
        param.put("payMethods", payMethods);

        JSONObject res = lianlianpayClient.postJson("/v1/txn/payment-bankcard", param);
        return res;

    }


    /**
     * 交易二次短信验证
     * @param userId
     * @param orderNo
     * @param totalAmount
     * @param token
     * @param verifyCode
     * @return
     */
    public JSONObject tradeValidationSms(Long userId, String orderNo, BigDecimal totalAmount, String token, String verifyCode){

        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        param.put("payer_type", "USER");//固定是用户付款
        param.put("payer_id", bizUserId);//固定是用户付款
        param.put("txn_seqno", orderNo);
        param.put("total_amount", totalAmount);
        param.put("token", token);
        param.put("verify_code", verifyCode);
        JSONObject res = lianlianpayClient.postJson("/v1/txn/validation-sms", param);
        return res;
    }


    /**
     * 支付订单查询
     * @param orderNo
     * @return
     */
    public JSONObject paymentQuery(String orderNo){
        JSONObject param = new JSONObject();
        param.put("txn_seqno", orderNo);//商户订单号
//        param.put("accp_txno", "");//ACCP系统交易单号
//        param.put("sub_chnl_no", "");//上有渠道流水号

        JSONObject res = lianlianpayClient.postJson("/v1/txn/query-payment", param);
        return res;
    }


    /**
     * 提现结果查询
     * @param orderNo
     * @return
     */
    public JSONObject withdrawQuery(String orderNo){
        JSONObject param = new JSONObject();
        param.put("txn_seqno", orderNo);//商户订单号
//        param.put("accp_txno", "");//ACCP系统交易单号
//        param.put("sub_chnl_no", "");//上有渠道流水号

        JSONObject res = lianlianpayClient.postJson("/v1/txn/query-withdrawal", param);
        return res;
    }

    /**
     * 交易流水
     * @param userId
     * @param pageQuery
     * @return
     */
    public JSONObject tradeLogList(Long userId, PageQuery pageQuery){
        String bizUserId = getBizUserId(userId);
        JSONObject param = new JSONObject();
        param.put("user_id", bizUserId);
        //用户类型。
        //INNERMERCHANT:商户
        //INNERUSER：个人用户
        //INNERCOMPANY：企业用户
        param.put("user_type", "INNERUSER");

        Map<String,Object> query = pageQuery.getQuery();
        String acctType = Objects.toString(query.get("acctType"), "");
        //USEROWN_PSETTLE	用户自有待结算账户
        //USEROWN_AVAILABLE 用户自有可用账户
        param.put("acct_type", acctType);

        //时间格式yyyyMMddHHmmss
        List dateRange = null;
        if(query.get("dateRange") instanceof  List){
            dateRange = (List)query.get("dateRange");
        }

        if(dateRange == null || dateRange.size() < 2){
            throw new BusinessException("日期范围缺失");
        }

        LocalDateTime startDate = DateUtil.parse(dateRange.get(0).toString()).toLocalDateTime();
        LocalDateTime endDate = DateUtil.parse(dateRange.get(1).toString()).toLocalDateTime();
        param.put("date_start", DateUtil.format(startDate, "yyyyMMddHHmmss"));
        param.put("date_end", DateUtil.format(endDate, "yyyyMMddHHmmss"));

        String flagDc = Objects.toString(query.get("flagDc"), "");
        param.put("flag_dc", flagDc);

        String sortType = Objects.toString(query.get("sortType"), "");
        param.put("sort_type", sortType);

        param.put("page_no", pageQuery.getPage() + 1);
        param.put("page_size", pageQuery.getSize());

        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/query-acctserial", param);
        return res;
    }

    /**
     * 销户申请
     * @return
     */
    public JSONObject cancelApply(UserFundAccount account, IdentityAuth identityAuth, String password, String randomKey){
        String bizUserId = getBizUserId(identityAuth.getUserId());
        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        JSONObject param = new JSONObject();
        param.put("userId", bizUserId);
        String txnseqno = String.valueOf(snowflakeIdWorker.nextId());
        param.put("txn_seqno", txnseqno);//销户订单号
        param.put("txn_time", txnTime);//商户系统交易时间
        String notfiyUrl = payHelper.resolveAccountCancelNotify();
        param.put("notify_url", notfiyUrl);
        param.put("id_type", "ID_CARD");
        param.put("id_no", identityAuth.getIdNo());
        param.put("reg_phone", account.getRegisterPhone());
        param.put("user_name", account.getAccountName());
        param.put("password", password );
        param.put("random_key", randomKey);

        JSONObject res = lianlianpayClient.postJson("/v1/acctmgr/cancel-apply", param);
        return res;
    }

    /**
     * 检查支付结果
     * @param orderNo
     * @return
     */
    public PayResult checkPayResult(String orderNo){
        PayResult.PayResultBuilder builder = PayResult.builder();
        //根据支付渠道识别
        JSONObject res = paymentQuery(orderNo);

        //设置结果

        String txnStatus = res.getString("txn_status");
        //支付完成时间,格式为yyyyMMddHHmmss
        String finishTime = res.getString("finish_time");

        String accpTxNo = res.getString("accp_txno");


        JSONObject orderInfo = res.getJSONObject("orderInfo");
        BigDecimal totalAmountObj = orderInfo.getBigDecimal("total_amount");

        String accNo = null;
        String accLogonNo = null;
        JSONArray payerInfoList = res.getJSONArray("payerInfo");
        if(payerInfoList != null && payerInfoList.size() > 0){
            JSONObject payerInfo = payerInfoList.getJSONObject(0);
            String payerType = payerInfo.getString("payer_type");
            String payerId = payerInfo.getString("payer_id");
            accNo = payerType + "("+payerId+")";
            accLogonNo = payerId;
        }


        String orderMsg = "";
        PayStatus payStatus = PayStatus.UNPAID;
        if("TRADE_SUCCESS".equals(txnStatus)){
            payStatus = PayStatus.HAVE_PAID;
            orderMsg = "交易成功";
        }else if("TRADE_WAIT_PAY".equals(txnStatus)){
            payStatus = PayStatus.PENDING;
            orderMsg = "交易处理中";
        }else if("TRADE_CLOSE".equals(txnStatus)){
            payStatus = PayStatus.FAILED_PAID;
            orderMsg = "交易失败";
        }

        LocalDateTime payTimeObj = null;
        if(StringUtils.isNotEmpty(finishTime)){
            payTimeObj = DateUtil.parse(finishTime).toLocalDateTime();
        }

        builder.orderNo(orderNo)
                .totalAmount(totalAmountObj)
                .status(payStatus)
                .transactionNo(accpTxNo)
                .payTime(payTimeObj)
                .orderMsg(orderMsg)
                .accNo(accNo)
                .accLogonNo(accLogonNo);
        return builder.build();

    }


    /**
     * 检查充值结果
     * @param orderNo
     * @return
     */
    public RechargeResult checkRechargeResult(String orderNo){
        RechargeResult.RechargeResultBuilder builder = RechargeResult.builder();
        //根据支付渠道识别
        JSONObject res = paymentQuery(orderNo);

        //设置结果

        String txnStatus = res.getString("txn_status");
        //支付完成时间,格式为yyyyMMddHHmmss
        String finishTime = res.getString("finish_time");

        String accpTxNo = res.getString("accp_txno");


        JSONObject orderInfo = res.getJSONObject("orderInfo");
        BigDecimal totalAmountObj = orderInfo.getBigDecimal("total_amount");

        String accNo = null;
        String accLogonNo = null;
        JSONArray payerInfoList = res.getJSONArray("payerInfo");
        if(payerInfoList != null && payerInfoList.size() > 0){
            JSONObject payerInfo = payerInfoList.getJSONObject(0);
            String payerType = payerInfo.getString("payer_type");
            String payerId = payerInfo.getString("payer_id");
            accNo = payerType + "("+payerId+")";
            accLogonNo = payerId;
        }


        String orderMsg = "";
        RechargeStatus  rechargeStatus = RechargeStatus.CREATED;
        if("TRADE_SUCCESS".equals(txnStatus)){
            rechargeStatus = RechargeStatus.SUCCESS;
            orderMsg = "交易成功";
        }else if("TRADE_WAIT_PAY".equals(txnStatus)){
            rechargeStatus = RechargeStatus.PENDING;
            orderMsg = "交易处理中";
        }else if("TRADE_CLOSE".equals(txnStatus)){
            rechargeStatus = RechargeStatus.FAILED;
            orderMsg = "交易失败";
        }

        LocalDateTime payTimeObj = null;
        if(StringUtils.isNotEmpty(finishTime)){
            payTimeObj = DateUtil.parse(finishTime).toLocalDateTime();
        }

        builder.orderNo(orderNo)
                .totalAmount(totalAmountObj)
                .status(rechargeStatus)
                .transactionNo(accpTxNo)
                .payTime(payTimeObj)
                .orderMsg(orderMsg)
                .accNo(accNo)
                .accLogonNo(accLogonNo);
        return builder.build();

    }


    /**
     * 检查提现结果
     * @param orderNo
     * @return
     */
    public WithdrawResult checkWithdrawResult(String orderNo){
        WithdrawResult.WithdrawResultBuilder builder = WithdrawResult.builder();
        //根据支付渠道识别
        JSONObject res = withdrawQuery(orderNo);

        //设置结果
        String txnStatus = res.getString("txn_status");
        //支付完成时间,格式为yyyyMMddHHmmss
        String finishTime = res.getString("finish_time");

        String accpTxNo = res.getString("accp_txno");


        JSONObject orderInfo = res.getJSONObject("orderInfo");
        BigDecimal totalAmountObj = orderInfo.getBigDecimal("total_amount");

        String accNo = null;
        String accLogonNo = null;
        //这里返回的不是数组
        JSONObject payerInfo = res.getJSONObject("payerInfo");
        if(payerInfo != null){
            String payerType = payerInfo.getString("payer_type");
            String payerId = payerInfo.getString("payer_id");
            accNo = payerType + "("+payerId+")";
            accLogonNo = payerId;
        }


        String orderMsg = "";
        WithdrawStatus withdrawStatus = WithdrawStatus.CREATED;
        if("TRADE_SUCCESS".equals(txnStatus)){
            withdrawStatus = WithdrawStatus.SUCCESS;
            orderMsg = "交易成功";
        }else if("TRADE_WAIT_PAY".equals(txnStatus)){
            withdrawStatus = WithdrawStatus.PENDING;
            orderMsg = "交易处理中";
        }else if("TRADE_CLOSE".equals(txnStatus)){
            withdrawStatus = WithdrawStatus.FAILED;
            orderMsg = "交易失败";
        }

        LocalDateTime payTimeObj = null;
        if(StringUtils.isNotEmpty(finishTime)){
            payTimeObj = DateUtil.parse(finishTime).toLocalDateTime();
        }

        builder.orderNo(orderNo)
                .totalAmount(totalAmountObj)
                .status(withdrawStatus)
                .transactionNo(accpTxNo)
                .payTime(payTimeObj)
                .orderMsg(orderMsg)
                .accNo(accNo)
                .accLogonNo(accLogonNo);
        return builder.build();

    }

    /**
     * 发送转账请求
     * @param userId
     * @param orderNo
     * @param totalAmount
     * @return
     */
    public JSONObject transferMoney(Long userId, String orderNo,  BigDecimal totalAmount, String reason){
        String bizUserId = getBizUserId(userId);

        JSONObject bodyJson = new JSONObject();
        bodyJson.put("notify_url", payHelper.resolveTransferNotifyUrl(orderNo));
        bodyJson.put("risk_item", getRiskItem(userId, reason));

        String txnTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        JSONObject orderInfo = new JSONObject();
        orderInfo.put("txn_seqno", orderNo);
        orderInfo.put("txn_time" , txnTime);
        orderInfo.put("total_amount", totalAmount);
        orderInfo.put("txn_purpose", "其他");

        bodyJson.put("orderInfo", orderInfo);

        JSONObject payerInfo = new JSONObject();
        //付款方类型。
        //用户：USER
        //平台商户：MERCHANT
        payerInfo.put("payer_type", "MERCHANT");
        payerInfo.put("payer_id", lianlianpayProperties.getMid() );
        //付款方账户类型。付款方类型为商户时需要指定平台商户账户类型。
        //USEROWN：用户自有可用账户。
        //MCHOWN：平台商户自有可用账户。
        payerInfo.put("payer_accttype", "MCHOWN");

        bodyJson.put("payerInfo", payerInfo);

        JSONObject payeeInfo = new JSONObject();
        payeeInfo.put("payee_type", "USER" );
        payeeInfo.put("payee_id", bizUserId);
        payeeInfo.put("payee_accttype", "MCHOWN");
        payeeInfo.put("payee_amount", totalAmount);

        bodyJson.put("payeeInfo", payeeInfo);

        JSONObject result = lianlianpayClient.postJson("/v1/txn/transfer-morepyee", bodyJson);
        return result;
    }


}
