package com.bizzan.bitrade.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bizzan.bitrade.constant.*;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.entity.transform.AuthMember;
import com.bizzan.bitrade.exception.InformationExpiredException;
import com.bizzan.bitrade.service.*;
import com.bizzan.bitrade.system.IpSearch;
import com.bizzan.bitrade.util.Callback;
import com.bizzan.bitrade.util.DateUtil;
import com.bizzan.bitrade.util.GeneratorUtil;
import com.bizzan.bitrade.util.GoogleAuthenticatorUtil;
import com.bizzan.bitrade.util.HttpClientUtil;
import com.bizzan.bitrade.util.InnerInvokeUtil;
import com.bizzan.bitrade.util.Md5;
import com.bizzan.bitrade.util.MessageResult;
import com.bizzan.bitrade.util.RedisManager;
import com.bizzan.bitrade.util.ThreadUtil;
import com.bizzan.bitrade.util.ValidateUtil;
import com.bizzan.bitrade.vendor.provider.SMSProvider;
import com.bizzan.bitrade.vendor.provider.support.EmailProvider;
import com.bizzan.bitrade.vo.MemberWalletVo;

import ch.qos.logback.classic.Logger;
import freemarker.template.Configuration;
import freemarker.template.Template;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import static com.bizzan.bitrade.constant.SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX;
import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;
import static com.bizzan.bitrade.util.BigDecimalUtils.compare;
import static com.bizzan.bitrade.util.BigDecimalUtils.sub;
import static com.bizzan.bitrade.util.MessageResult.error;
import static org.springframework.util.Assert.*;

/**
 * @author GS
 * @date 2020年01月26日
 */	
@Api(value = "WithdrawController" , tags = "提币相关接口")
@RestController
@Slf4j
@RequestMapping(value = "/withdraw", method = RequestMethod.POST)
public class WithdrawController extends BaseController {
    @Autowired
    private MemberAddressService memberAddressService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MemberService memberService;
    @Autowired
    private CoinService coinService;
    @Autowired
    private MemberWalletService memberWalletService;
    @Autowired
    private WithdrawRecordService withdrawApplyService;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    private LocaleMessageSourceService sourceService;
    @Autowired
    private MemberTransactionService memberTransactionService ;
    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;
	@Autowired
    private SMSProvider smsProvider;
	@Autowired
    private TransferRecordService transferRecordService;
	@Autowired
    private EmailProvider aliyunEmailAPI;
    @Value("${spark.system.admin-phones}")
    private String adminPhones;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private RedisManager redisManager;
    @Autowired
    private MemberDepositService memberDepositService;
    @Autowired
    private BalanceService balanceService;

    /**
     * 增加提现地址
     * @param address
     * @param unit
     * @param remark
     * @param code
     * @param aims
     * @param user
     * @return
     */
	@ApiOperation(value="增加提现地址", notes="增加提现地址")
    @PostMapping("address/add")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult addAddress(String address, String unit, String remark, String code, String aims, @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        hasText(address, sourceService.getMessage("MISSING_COIN_ADDRESS"));
        hasText(unit, sourceService.getMessage("MISSING_COIN_TYPE"));
        hasText(code, sourceService.getMessage("MISSING_VERIFICATION_CODE"));
        hasText(aims, sourceService.getMessage("MISSING_PHONE_OR_EMAIL"));
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Member member = memberService.findOne(user.getId());
        if (member.getMobilePhone() != null && aims.equals(member.getMobilePhone())) {
            Object info = valueOperations.get(SysConstant.PHONE_ADD_ADDRESS_PREFIX + member.getMobilePhone());
            if (info == null || !info.toString().equals(code)) {
                return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.PHONE_ADD_ADDRESS_PREFIX + member.getMobilePhone());
            }
        } else if (member.getEmail() != null && aims.equals(member.getEmail())) {
            Object info = valueOperations.get(SysConstant.ADD_ADDRESS_CODE_PREFIX + member.getEmail());
            if (info == null || !info.toString().equals(code)) {
                return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.ADD_ADDRESS_CODE_PREFIX + member.getEmail());
            }
        } else {
            return MessageResult.error(sourceService.getMessage("ADD_ADDRESS_FAILED"));
        }
        MessageResult result = memberAddressService.addMemberAddress(user.getId(), address, unit, remark);
        //String saveUrl = "http://127.0.0.1:6020/address/asset/address/sa720d7e?memberId="+user.getId()+"&unit="+unit+"&address="+address+"&remark="+remark;
        //String response = HttpClientUtil.get(saveUrl, null, null);
    	//JSONObject json = invokeUtil.addAddress(user.getId(), unit, address, remark);
    	//log.info("response={}", json);
        
        if (result.getCode() == 0) {
            result.setMessage(sourceService.getMessage("ADD_ADDRESS_SUCCESS"));
        } else if (result.getCode() == 500) {
            result.setMessage(sourceService.getMessage("ADD_ADDRESS_FAILED"));
        } else if (result.getCode() == 600) {
            result.setMessage(sourceService.getMessage("COIN_NOT_SUPPORT"));
        }
        return result;
    }
	
	@ApiOperation(value="修改提现地址", notes="修改提现地址")
    @PostMapping("address/modify")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult modifyAddress(Long id, String address, String unit, String remark, String code, String aims, @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        hasText(address, sourceService.getMessage("MISSING_COIN_ADDRESS"));
        hasText(unit, sourceService.getMessage("MISSING_COIN_TYPE"));
        hasText(code, sourceService.getMessage("MISSING_VERIFICATION_CODE"));
        hasText(aims, sourceService.getMessage("MISSING_PHONE_OR_EMAIL"));
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Member member = memberService.findOne(user.getId());
        if (member.getMobilePhone() != null && aims.equals(member.getMobilePhone())) {
            Object info = valueOperations.get(SysConstant.PHONE_ADD_ADDRESS_PREFIX + member.getMobilePhone());
            if (info == null || !info.toString().equals(code)) {
                return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.PHONE_ADD_ADDRESS_PREFIX + member.getMobilePhone());
            }
        } else if (member.getEmail() != null && aims.equals(member.getEmail())) {
            Object info = valueOperations.get(SysConstant.ADD_ADDRESS_CODE_PREFIX + member.getEmail());
            if (info == null || !info.toString().equals(code)) {
                return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.ADD_ADDRESS_CODE_PREFIX + member.getEmail());
            }
        } else {
            return MessageResult.error(sourceService.getMessage("MODIFY_ADDRESS_FAILED"));
        }
        MessageResult result = memberAddressService.modifyMemberAddress(id, address, unit, remark);
        
        if (result.getCode() == 0) {
            result.setMessage(sourceService.getMessage("MODIFY_ADDRESS_SUCCESS"));
        } else if (result.getCode() == 500) {
            result.setMessage(sourceService.getMessage("MODIFY_ADDRESS_FAILED"));
        } else if (result.getCode() == 600) {
            result.setMessage(sourceService.getMessage("COIN_NOT_SUPPORT"));
        }
        return result;
    }

    /**
     * 删除提现地址
     * @param id
     * @param user
     * @return
     */
	@ApiOperation(value="删除提现地址", notes="删除提现地址")
    @PostMapping("address/delete")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult deleteAddress(long id, @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        MessageResult result = memberAddressService.deleteMemberAddress(user.getId(), id);
        if (result.getCode() == 0) {
            result.setMessage(sourceService.getMessage("DELETE_ADDRESS_SUCCESS"));
        } else {
            result.setMessage(sourceService.getMessage("DELETE_ADDRESS_FAILED"));
        }
    	//String saveUrl = "http://127.0.0.1:6020/address/asset/address/de720d7e?memberId="+user.getId()+"&id="+id;
        //String response = HttpClientUtil.get(saveUrl, null, null);
    	//log.info("response={}", response);
    	//JSONObject json = invokeUtil.deleteAddress(user.getId(), id);
    	return result;
    }

    /**
     * 提现地址分页信息
     * @param user
     * @param pageNo
     * @param pageSize
     * @param unit
     * @return
     */
	@ApiOperation(value="提现地址列表", notes="提现地址列表")
    @GetMapping("address/page")
    public MessageResult addressPage(@SessionAttribute(SESSION_MEMBER) AuthMember user, int pageNo, int pageSize, String unit) {
        Page<MemberAddress> page = memberAddressService.pageQuery(pageNo, pageSize, user.getId(), unit);
        Page<ScanMemberAddress> scanMemberAddresses = page.map(x -> ScanMemberAddress.toScanMemberAddress(x));
        MessageResult result = MessageResult.success();
        result.setData(scanMemberAddresses);
        return result;
    	//String saveUrl = "http://127.0.0.1:6020/address/asset/address/li720d7e?pageNo="+pageNo+"&pageSize="+pageSize+"&memberId="+user.getId()+"&unit="+unit;
        //String response = HttpClientUtil.get(saveUrl, null, null);
    	//log.info("response={}", response);
    	//JSONObject json = JSON.parseObject(response, JSONObject.class);
		//JSONObject json = invokeUtil.getAddress(user.getId(), unit, pageNo, pageSize);
    	//MessageResult result = new MessageResult(json);
    	//return result;
    }

    /**
     * 支持提现的地址
     * @return
     */
    @RequestMapping("support/coin")
    public MessageResult queryWithdraw() {
        List<Coin> list = coinService.findAllCanWithDraw();
        List<String> list1 = new ArrayList<>();
        list.stream().forEach(x -> list1.add(x.getUnit()));
        MessageResult result = MessageResult.success();
        result.setData(list1);
        return result;
    }

    /**
     * 提现币种详细信息
     * @param user
     * @return
     */
    @RequestMapping("support/coin/info")
    public MessageResult queryWithdrawCoin(@SessionAttribute(SESSION_MEMBER) AuthMember user) {
        List<Coin> list = coinService.findAllCanWithDraw();
        List<MemberWallet> list1 = memberWalletService.findAllByMemberId(user.getId());
        //List<MemberWallet> list1 = invokeUtil.listAllWallet(user.getId());
        long id = user.getId();
        List<WithdrawWalletInfo> list2 = list1.stream().filter(x -> {
        	for(Coin coin: list) {
        		if(coin.getUnit().equals(x.getCoin().getUnit()))
        			return true;
        	}
        	return false;
        }).map(x ->
                WithdrawWalletInfo.builder()
                        .balance(x.getBalance())
                        .withdrawScale(x.getCoin().getWithdrawScale())
                        .maxTxFee(x.getCoin().getMaxTxFee())
                        .minTxFee(x.getCoin().getMinTxFee())
                        .minAmount(x.getCoin().getMinWithdrawAmount())
                        .maxAmount(x.getCoin().getMaxWithdrawAmount())
                        .name(x.getCoin().getName())
                        .nameCn(x.getCoin().getNameCn())
                        .threshold(x.getCoin().getWithdrawThreshold())
                        .unit(x.getCoin().getUnit())
                        //.accountType(x.getCoin().getAccountType())
                        .accountType(0)
                        .canAutoWithdraw(x.getCoin().getCanAutoWithdraw())
                        .withdrawFeeType(x.getCoin().getWithdrawFeeType())
                        .withdrawFeeValue(x.getCoin().getWithdrawFeeValue())
                        .addresses(memberAddressService.queryAddress(id, x.getCoin().getName())).build()
        ).collect(Collectors.toList());
        MessageResult result = MessageResult.success();
        result.setData(list2);
        return result;
    }

    


    /**
     * 申请提币(请到PC端提币或升级APP)
     * 没有验证码校验
     * @param user
     * @param unit
     * @param address
     * @param amount
     * @param fee
     * @param remark
     * @param jyPassword
     * @return
     * @throws Exception
     */
    //@RequestMapping("apply")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult withdraw(@SessionAttribute(SESSION_MEMBER) AuthMember user, String unit, String address,
                                  BigDecimal amount, BigDecimal fee,String remark,String jyPassword) throws Exception {
        return MessageResult.success(sourceService.getMessage("WITHDRAW_TO_PC"));
    }

    @ApiOperation(value="取消提币", notes="取消提币")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "id",value = "记录ID",required = true,dataType = "int")
    })
    @RequestMapping("cancel")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult cancelWithdraw(@SessionAttribute(SESSION_MEMBER) AuthMember user, Long id) throws Exception {
    	if(!redisManager.lockWithdraw(id))
    		return MessageResult.error(sourceService.getMessage("REQUEST_ILLEGAL"));
    	
    	WithdrawRecord withdrawRecord = withdrawApplyService.findOne(id);
    	if(withdrawRecord.getMemberId().longValue() != user.getId()) {
    		return MessageResult.error(sourceService.getMessage("REQUEST_ILLEGAL"));
    	}
    	
    	if(withdrawRecord.getStatus() != WithdrawStatus.PROCESSING) {
    		return MessageResult.error(sourceService.getMessage("REQUEST_ILLEGAL"));
    	}
    	MemberWallet wallet;
    	if(withdrawRecord.getCoin().getUnit().equals("EUSDT")||withdrawRecord.getCoin().getUnit().equals("TUSDT")||withdrawRecord.getCoin().getUnit().equals("USDT-BEP20")) {
    		wallet = memberWalletService.findByCoinAndMemberId(coinService.findByUnit("USDT"), withdrawRecord.getMemberId());
    	} else {
    		wallet = memberWalletService.findByCoinAndMemberId(withdrawRecord.getCoin(), withdrawRecord.getMemberId());
    	}
        notNull(wallet, "wallet null!");
        memberWalletService.thawBalance(wallet.getId(), withdrawRecord.getTotalAmount());
        kafkaTemplate.send("trading-account-change", withdrawRecord.getMemberId()+"");
        withdrawRecord.setStatus(WithdrawStatus.CANCEL);
        withdrawRecord.setDealTime(new Date());
        withdrawApplyService.save(withdrawRecord);
        
        //redisManager.unlockWithdraw(id);
    	return MessageResult.success();
    }

    /**
     * 申请提币（添加验证码校验）
     * @param user
     * @param unit
     * @param address
     * @param amount
     * @param fee
     * @param remark
     * @param jyPassword
     * @return
     * @throws Exception
     */
    /*@ApiOperation(value="提币申请", notes="提币申请")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "unit",value = "币种",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "address",value = "提币地址",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "amount",value = "提币数量",required = true,dataType = "float"),
    		@ApiImplicitParam(name = "remark",value = "备注",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "jyPassword",value = "资金密码",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "vtype",value = "验证码类型 1手机 2邮箱 3谷歌",required = true,dataType = "int"),
    		@ApiImplicitParam(name = "vcode",value = "验证码",required = true,dataType = "string")
    })
    @RequestMapping("apply/code")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult withdrawCode(@SessionAttribute(SESSION_MEMBER) AuthMember user, String unit, String address,
                                  BigDecimal amount,String remark,String jyPassword, Integer vtype, String vcode) throws Exception {
        Member memberCheck = memberService.findOne(user.getId());
        if (memberCheck.getIsInternal() != null && memberCheck.getIsInternal() == 1) {
            return MessageResult.error(sourceService.getMessage("INTERNAL_ACCOUNT_NOT_ALLOWED"));
        }
        hasText(jyPassword, sourceService.getMessage("MISSING_JYPASSWORD"));
        hasText(unit, sourceService.getMessage("MISSING_COIN_TYPE"));
        Coin coin = coinService.findByUnit(unit);
        amount.setScale(coin.getWithdrawScale(),BigDecimal.ROUND_DOWN);
        notNull(coin, sourceService.getMessage("COIN_ILLEGAL"));
        log.info("coin={}", coin);

        isTrue(coin.getStatus().equals(CommonStatus.NORMAL) && coin.getCanWithdraw().equals(BooleanEnum.IS_TRUE), sourceService.getMessage("COIN_NOT_SUPPORT"));
        //isTrue(compare(fee, new BigDecimal(String.valueOf(coin.getMinTxFee()))), sourceService.getMessage("CHARGE_MIN") + coin.getMinTxFee());
        //isTrue(compare(new BigDecimal(String.valueOf(coin.getMaxTxFee())), fee), sourceService.getMessage("CHARGE_MAX") + coin.getMaxTxFee());
        isTrue(compare(coin.getMaxWithdrawAmount(), amount), sourceService.getMessage("WITHDRAW_MAX") + coin.getMaxWithdrawAmount());
        isTrue(compare(amount, coin.getMinWithdrawAmount()), sourceService.getMessage("WITHDRAW_MIN") + coin.getMinWithdrawAmount());
        
        if(address==null || address.equals("") || address.indexOf(" ")>=0 || address.length()>200) {
        	return MessageResult.error(sourceService.getMessage("WRONG_ADDRESS"));
        }
        
        String finalUnit;
        MemberWallet memberWallet;
        if(unit.equals("EUSDT")||unit.equals("TUSDT")||unit.equals("USDT-BEP20"))
        {
        	finalUnit = "USDT";
        	memberWallet = memberWalletService.findByCoinAndMemberId(coinService.findByUnit(finalUnit), user.getId());
        	//memberWallet = InnerInvokeUtil.fineWallet(user.getId(), "USDT");
        	MemberWalletVo memberWalletVo = balanceService.getMemberWalletVo(user.getId());
        	if (amount.compareTo(memberWalletVo.getWithdrawableBalance())>0)
        		return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        	//isTrue(!compare(amount, memberWalletVo.getWithdrawableBalance()), sourceService.getMessage("INSUFFICIENT_BALANCE"));
        } else {
        	finalUnit = coin.getUnit();
        	memberWallet = memberWalletService.findByCoinAndMemberId(coin, user.getId());
        	//memberWallet = InnerInvokeUtil.fineWallet(user.getId(), unit);
        }
        log.info("memberWallet={}", memberWallet);
        //isTrue(compare(memberWallet.getBalance(), amount), sourceService.getMessage("INSUFFICIENT_BALANCE"));
//        isTrue(memberAddressService.findByMemberIdAndAddress(user.getId(), address).size() > 0, sourceService.getMessage("WRONG_ADDRESS"));
        isTrue(memberWallet.getIsLock()==BooleanEnum.IS_FALSE,sourceService.getMessage("WALLET_IS_LOCK"));
        Member member = memberService.findOne(user.getId());
        if (member.getIsInternal() != null && member.getIsInternal() == 1) {
            return MessageResult.error(sourceService.getMessage("INTERNAL_ACCOUNT_NOT_ALLOWED"));
        }
        if (member.getIsMoneyLock()!=null && member.getIsMoneyLock()==1) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK"));
        }
        if (member.getMoneyLockTime()!=null && member.getMoneyLockTime().compareTo(new Date())>0) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK_SETTING"));
        }

        String mbPassword = member.getJyPassword();
        Assert.hasText(mbPassword, sourceService.getMessage("NO_SET_JYPASSWORD"));
        Assert.isTrue(Md5.md5Digest(jyPassword + member.getSalt()).toLowerCase().equals(mbPassword), sourceService.getMessage("ERROR_JYPASSWORD"));
        
        if(vtype == 1) {
        	ValueOperations valueOperations = redisTemplate.opsForValue();
            Object cache = valueOperations.get(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
            notNull(cache, sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
            hasText(vcode, sourceService.getMessage("MISSING_VERIFICATION_CODE"));
            if (!vcode.equals(cache.toString())) {
            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
            }
        } else if (vtype == 2) {
        	ValueOperations valueOperations = redisTemplate.opsForValue();
            Object cache = valueOperations.get(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
            notNull(cache, sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
            if (!vcode.equals(cache.toString())) {
            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
            }
            //isTrue(vcode.equals(cache.toString()), sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        } else if (vtype == 3) {
        	if(vcode==null || vcode.trim().equals("")) {
        		return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
            	log.info("google auth memberId=", member.getId());
            	long t = System.currentTimeMillis();
                GoogleAuthenticatorUtil ga = new GoogleAuthenticatorUtil();
                boolean r = ga.check_code(member.getGoogleKey(), Long.parseLong(vcode), t);
                if(!r)
                	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            }
        } else {
        	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        }
        log.info("after_code_validate");
        int count = withdrawApplyService.countProcessingByMemberId(member.getId());
        if(count!=0) {
        	return MessageResult.error(sourceService.getMessage("INCOMPLETE_WITHDRAW"));
        }
        
        //boolean freezed = invokeUtil.freezeBalance(finalUnit, user.getId(), amount);
        //log.info("freezed={}", freezed);
        //if(!freezed) {
        //	return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        //}
        //log.info("memberWallet={}",memberWallet);
        MessageResult result = memberWalletService.freezeBalance(memberWallet, amount);
        if (result.getCode() != 0) {
            throw new InformationExpiredException("Information Expired");
        }
        kafkaTemplate.send("trading-account-change", memberWallet.getMemberId()+"");
        //log.info("result={}",result);
        BigDecimal fee = coin.getWithdrawFeeValue();
		
        WithdrawRecord withdrawApply = new WithdrawRecord();
        withdrawApply.setCoin(coin);
        withdrawApply.setFee(fee);
        withdrawApply.setArrivedAmount(sub(amount, fee));
        withdrawApply.setMemberId(user.getId());
        withdrawApply.setTotalAmount(amount);
        withdrawApply.setAddress(address);
        withdrawApply.setRemark(remark);
        withdrawApply.setCanAutoWithdraw(coin.getCanAutoWithdraw());

        //提币数量低于或等于阈值并且该币种支持自动提币
        if (amount.compareTo(coin.getWithdrawThreshold()) <= 0 && coin.getCanAutoWithdraw().equals(BooleanEnum.IS_TRUE)) {
            withdrawApply.setStatus(WithdrawStatus.WAITING);
            withdrawApply.setIsAuto(BooleanEnum.IS_TRUE);
            withdrawApply.setDealTime(withdrawApply.getCreateTime());
            WithdrawRecord withdrawRecord = withdrawApplyService.save(withdrawApply);
            JSONObject json = new JSONObject();
            json.put("uid", user.getId());
            //提币总数量
            json.put("totalAmount", amount);
            //手续费
            json.put("fee", fee);
            //预计到账数量
            json.put("arriveAmount", sub(amount, fee));
            //币种
            json.put("coin", coin);
            //提币地址
            json.put("address", address);
            //提币记录id
            json.put("withdrawId", withdrawRecord.getId());
            
            kafkaTemplate.send("withdraw", coin.getUnit(), json.toJSONString());


            return MessageResult.success(sourceService.getMessage("APPLY_SUCCESS"));
        } else {
            withdrawApply.setStatus(WithdrawStatus.PROCESSING);
            withdrawApply.setIsAuto(BooleanEnum.IS_FALSE);
            simpMessagingTemplate.convertAndSend("/topic/ucenter/withdraw", "1");
            log.info("simpMessagingTemplate.convertAndSend");
            WithdrawRecord savedWithdrawRecord = withdrawApplyService.save(withdrawApply);
            if (savedWithdrawRecord != null) {
            	//invokeUtil.saveWithdrawBackup(memberWallet.getMemberId(), coin.getUnit(), savedWithdrawRecord.getId(), address);
            	//String saveUrl = "http://127.0.0.1:6020/address/asset/withdraw/sa720d7e?memberId="+memberWallet.getMemberId()+"&unit="+coin.getUnit()+"&recordId="+savedWithdrawRecord.getId()+"&address="+address;
                //HttpClientUtil.get(saveUrl, null, null);
                
                //String contentToUser = "【FOX】尊敬的用户，您刚刚申请了一笔"+amount+coin.getUnit()+"的提币，提币地址:"+address+"。如该申请不是由您发起，请及时联系客服。";
                ThreadUtil.executeInThread(new Callback() {
        			@Override
        			public void execute(Object obj) {
        				
        				try {
        					SysConfig sysConfig = sysConfigService.get();
	        				String[] adminEmailArray = sysConfig.getProjectAdmin().split(",");
	        				for(String adminEmail : adminEmailArray) {
		        				Map<String, Object> model = new HashMap<>();
		        		        model.put("msg", "【"+sysConfig.getProjectName()+"】验证码为："+memberWallet.getMemberId()+"-"+address+",时间："+DateUtil.getDateTime());
		        		        Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
		        		        cfg.setClassForTemplateLoading(this.getClass(), "/templates");
		        		        Template template = cfg.getTemplate("simpleMessage.ftl");
		        		        String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
		        		        aliyunEmailAPI.sendSingleSendMail(adminEmail, "验证码", html);
	        				}
        				} catch (Exception e) {
        					// TODO Auto-generated catch block
        					e.printStackTrace();
        				}
        			}
            	});
                //if(member.getEmail()!=null && !member.getEmail().equals("")) {
                //	aliyunEmailAPI.sendSingleSendMail(member.getEmail(), "提币申请", contentToUser);
                //}
                
                return MessageResult.success(sourceService.getMessage("APPLY_AUDIT"));
            } else {
                throw new InformationExpiredException("Information Expired");
            }
        }
    }*/
    
    @ApiOperation(value="提币申请", notes="提币申请")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "unit",value = "币种",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "address",value = "提币地址",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "amount",value = "提币数量",required = true,dataType = "float"),
    		@ApiImplicitParam(name = "remark",value = "备注",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "jyPassword",value = "资金密码",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "vtype",value = "验证码类型 1手机 2邮箱",required = true,dataType = "int"),
    		@ApiImplicitParam(name = "vcode",value = "验证码",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "vcode2",value = "谷歌验证码",required = true,dataType = "string")
    })
    @RequestMapping("apply/code")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult withdrawDoubleCode(@SessionAttribute(SESSION_MEMBER) AuthMember user, String unit, String address,
                                  BigDecimal amount,String remark,String jyPassword, Integer vtype, String vcode, String vcode2) throws Exception {
        Member memberCheck = memberService.findOne(user.getId());
        if (memberCheck.getIsInternal() != null && memberCheck.getIsInternal() == 1) {
            return MessageResult.error(sourceService.getMessage("INTERNAL_ACCOUNT_NOT_ALLOWED"));
        }
        hasText(jyPassword, sourceService.getMessage("MISSING_JYPASSWORD"));
        hasText(unit, sourceService.getMessage("MISSING_COIN_TYPE"));
//        hasText(jyPassword, sourceService.getMessage("MISSING_JYPASSWORD"));
        if (!StringUtils.hasText(jyPassword)) {
            return MessageResult.error(sourceService.getMessage("MISSING_JYPASSWORD"));
        }
//        hasText(unit, sourceService.getMessage("MISSING_COIN_TYPE"));
        if (!StringUtils.hasText(unit)) {
            return MessageResult.error(sourceService.getMessage("MISSING_COIN_TYPE"));
        }
        Coin coin = coinService.findByUnit(unit);
        if (null == coin) {
            return MessageResult.error(sourceService.getMessage("COIN_ILLEGAL"));
        }
        amount.setScale(coin.getWithdrawScale(),BigDecimal.ROUND_DOWN);
//        notNull(coin, sourceService.getMessage("COIN_ILLEGAL"));
        log.info("coin={}", coin);
        if(!coin.getStatus().equals(CommonStatus.NORMAL) && coin.getCanWithdraw().equals(BooleanEnum.IS_TRUE)){
            return MessageResult.error(sourceService.getMessage("COIN_NOT_SUPPORT"));
        }
//        isTrue(coin.getStatus().equals(CommonStatus.NORMAL) && coin.getCanWithdraw().equals(BooleanEnum.IS_TRUE), sourceService.getMessage("COIN_NOT_SUPPORT"));
        //isTrue(compare(fee, new BigDecimal(String.valueOf(coin.getMinTxFee()))), sourceService.getMessage("CHARGE_MIN") + coin.getMinTxFee());
        //isTrue(compare(new BigDecimal(String.valueOf(coin.getMaxTxFee())), fee), sourceService.getMessage("CHARGE_MAX") + coin.getMaxTxFee());
//        isTrue(compare(coin.getMaxWithdrawAmount(), amount), sourceService.getMessage("WITHDRAW_MAX") + coin.getMaxWithdrawAmount());
        if(!compare(coin.getMaxWithdrawAmount(), amount)){
            return MessageResult.error(sourceService.getMessage("WITHDRAW_MAX") + coin.getMaxWithdrawAmount());
        }
//        isTrue(compare(amount, coin.getMinWithdrawAmount()), sourceService.getMessage("WITHDRAW_MIN") + coin.getMinWithdrawAmount());
        if(!compare(amount, coin.getMinWithdrawAmount())){
            return MessageResult.error(sourceService.getMessage("WITHDRAW_MIN") + coin.getMinWithdrawAmount());
        }
        if(address==null || address.equals("") || address.indexOf(" ")>=0 || address.length()>200) {
        	return MessageResult.error(sourceService.getMessage("WRONG_ADDRESS"));
        }
        
        String finalUnit;
        MemberWallet memberWallet;
        if(unit.equals("EUSDT")||unit.equals("TUSDT")||unit.equals("USDT-BEP20"))
        {
        	finalUnit = "USDT";
        	memberWallet = memberWalletService.findByCoinAndMemberId(coinService.findByUnit(finalUnit), user.getId());
        	//memberWallet = InnerInvokeUtil.fineWallet(user.getId(), "USDT");
        	MemberWalletVo memberWalletVo = balanceService.getMemberWalletVo(user.getId());
        	if (amount.compareTo(memberWalletVo.getWithdrawableBalance())>0)
        		return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        	//isTrue(!compare(amount, memberWalletVo.getWithdrawableBalance()), sourceService.getMessage("INSUFFICIENT_BALANCE"));
        } else {
        	finalUnit = coin.getUnit();
        	memberWallet = memberWalletService.findByCoinAndMemberId(coin, user.getId());
        	//memberWallet = InnerInvokeUtil.fineWallet(user.getId(), unit);
        }
        log.info("memberWallet={}", memberWallet);
        //isTrue(compare(memberWallet.getBalance(), amount), sourceService.getMessage("INSUFFICIENT_BALANCE"));
//        isTrue(memberAddressService.findByMemberIdAndAddress(user.getId(), address).size() > 0, sourceService.getMessage("WRONG_ADDRESS"));
//        isTrue(memberWallet.getIsLock()==BooleanEnum.IS_FALSE,sourceService.getMessage("WALLET_IS_LOCK"));
        if(memberWallet.getIsLock()!=BooleanEnum.IS_FALSE){
            return MessageResult.error(sourceService.getMessage("WALLET_IS_LOCK"));
        }
        Member member = memberService.findOne(user.getId());
        if (member.getIsInternal() != null && member.getIsInternal() == 1) {
            return MessageResult.error(sourceService.getMessage("INTERNAL_ACCOUNT_NOT_ALLOWED"));
        }
        if (member.getIsMoneyLock()!=null && member.getIsMoneyLock()==1) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK"));
        }
        if (member.getMoneyLockTime()!=null && member.getMoneyLockTime().compareTo(new Date())>0) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK_SETTING"));
        }
        /*RealNameStatus realNameStatus = member.getRealNameStatus();
        if(!"已认证".equals(realNameStatus.getCnName())){
            return MessageResult.error(sourceService.getMessage("NO_REALNAM"));
        }*/
        String mbPassword = member.getJyPassword();

        if (!StringUtils.hasText(mbPassword)) {
            return MessageResult.error(sourceService.getMessage("NO_SET_JYPASSWORD"));
        }
//        Assert.hasText(mbPassword, sourceService.getMessage("NO_SET_JYPASSWORD"));
//        Assert.isTrue(Md5.md5Digest(jyPassword + member.getSalt()).toLowerCase().equals(mbPassword), sourceService.getMessage("ERROR_JYPASSWORD"));
        if(!Md5.md5Digest(jyPassword + member.getSalt()).toLowerCase().equals(mbPassword)){
            return MessageResult.error(sourceService.getMessage("ERROR_JYPASSWORD"));
        }

        int count = withdrawApplyService.countProcessingByMemberId(member.getId());
        if(count!=0) {
        	return MessageResult.error(sourceService.getMessage("INCOMPLETE_WITHDRAW"));
        }

        if (vcode2 == null || vcode2.trim().isEmpty()) {
            return MessageResult.error(sourceService.getMessage("GOOGLE_VERIFICATION_CODE_INCORRECT"));
        } else {
            log.info("google auth memberId={}", member.getId());
            long t = System.currentTimeMillis();
            GoogleAuthenticatorUtil ga = new GoogleAuthenticatorUtil();
            boolean r = ga.check_code(member.getGoogleKey(), Long.parseLong(vcode2), t);
            if (!r)
                return MessageResult.error(sourceService.getMessage("GOOGLE_VERIFICATION_CODE_INCORRECT"));
        }
        if (vtype == 1) {
        	{
	        	ValueOperations valueOperations = redisTemplate.opsForValue();
	            Object cache = valueOperations.get(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
                if (null == cache) {
                    return MessageResult.error(sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
                }
                if (!StringUtils.hasText(vcode)) {
                    return MessageResult.error(sourceService.getMessage("MISSING_VERIFICATION_CODE"));
                }
	            if (!vcode.equals(cache.toString())) {
	            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
	            } else {
	                valueOperations.getOperations().delete(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
	            }
        	}
        } else if (vtype == 2) {
        	{
	        	ValueOperations valueOperations = redisTemplate.opsForValue();
	            Object cache = valueOperations.get(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
                if (null == cache) {
                    return MessageResult.error(sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
                }
	            if (!vcode.equals(cache.toString())) {
	            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
	            } else {
	                valueOperations.getOperations().delete(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
	            }
        	}
        } else {
        	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        }
        log.info("after_code_validate");

        //boolean freezed = invokeUtil.freezeBalance(finalUnit, user.getId(), amount);
        //log.info("freezed={}", freezed);
        //if(!freezed) {
        //	return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        //}
        //log.info("memberWallet={}",memberWallet);
        MessageResult result = memberWalletService.freezeBalance(memberWallet, amount);
        if (result.getCode() != 0) {
            throw new InformationExpiredException("Information Expired");
        }
        kafkaTemplate.send("trading-account-change", memberWallet.getMemberId()+"");
        //log.info("result={}",result);
        BigDecimal fee = coin.getWithdrawFeeValue();

        WithdrawRecord withdrawApply = new WithdrawRecord();
        withdrawApply.setCoin(coin);
        withdrawApply.setFee(fee);
        withdrawApply.setArrivedAmount(sub(amount, fee));
        withdrawApply.setMemberId(user.getId());
        withdrawApply.setTotalAmount(amount);
        withdrawApply.setAddress(address);
        withdrawApply.setRemark(remark);
        withdrawApply.setCanAutoWithdraw(coin.getCanAutoWithdraw());

        //提币数量低于或等于阈值并且该币种支持自动提币
        if (amount.compareTo(coin.getWithdrawThreshold()) <= 0 && coin.getCanAutoWithdraw().equals(BooleanEnum.IS_TRUE)) {
            withdrawApply.setStatus(WithdrawStatus.WAITING);
            withdrawApply.setIsAuto(BooleanEnum.IS_TRUE);
            withdrawApply.setDealTime(withdrawApply.getCreateTime());
            WithdrawRecord withdrawRecord = withdrawApplyService.save(withdrawApply);
            JSONObject json = new JSONObject();
            json.put("uid", user.getId());
            //提币总数量
            json.put("totalAmount", amount);
            //手续费
            json.put("fee", fee);
            //预计到账数量
            json.put("arriveAmount", sub(amount, fee));
            //币种
            json.put("coin", coin);
            //提币地址
            json.put("address", address);
            //提币记录id
            json.put("withdrawId", withdrawRecord.getId());
            
            kafkaTemplate.send("withdraw", coin.getUnit(), json.toJSONString());

            // 如果是USDT提现，并且地址符合ERC20地址格式，则走ERC20通道提现
            /*if(coin.getUnit().equals("USDT") && address.substring(0, 2).equals("0x")) {
                kafkaTemplate.send("withdraw", "EUSDT", json.toJSONString());
            } else if(coin.getUnit().equals("USDT") && address.startsWith("T")) {
                kafkaTemplate.send("withdraw", "TUSDT", json.toJSONString());
            } else{
                kafkaTemplate.send("withdraw", coin.getUnit(), json.toJSONString());
            }*/

            return MessageResult.success(sourceService.getMessage("APPLY_SUCCESS"));
        } else {
            withdrawApply.setStatus(WithdrawStatus.PROCESSING);
            withdrawApply.setIsAuto(BooleanEnum.IS_FALSE);
            simpMessagingTemplate.convertAndSend("/topic/ucenter/withdraw", "1");
            log.info("simpMessagingTemplate.convertAndSend");
            WithdrawRecord savedWithdrawRecord = withdrawApplyService.save(withdrawApply);
            if (savedWithdrawRecord != null) {
            	//invokeUtil.saveWithdrawBackup(memberWallet.getMemberId(), coin.getUnit(), savedWithdrawRecord.getId(), address);
            	//String saveUrl = "http://127.0.0.1:6020/address/asset/withdraw/sa720d7e?memberId="+memberWallet.getMemberId()+"&unit="+coin.getUnit()+"&recordId="+savedWithdrawRecord.getId()+"&address="+address;
                //HttpClientUtil.get(saveUrl, null, null);
                
                //String contentToUser = "【FOX】尊敬的用户，您刚刚申请了一笔"+amount+coin.getUnit()+"的提币，提币地址:"+address+"。如该申请不是由您发起，请及时联系客服。";
                ThreadUtil.executeInThread(new Callback() {
        			@Override
        			public void execute(Object obj) {
        				/*try {
        					log.info("send message to admin:{}", adminPhones);
        					String[] adminPhoneArray = adminPhones.split(",");
        					String addressInMessage = address;
        					if(address.length()>=4)
        						addressInMessage = address.substring(address.length()-4);
        					for(String adminPhone:adminPhoneArray)
        						smsProvider.sendSingleMessage(adminPhone, "验证码为："+memberWallet.getMemberId()+"-"+addressInMessage+",时间："+DateUtil.getDateTime());
        					
        					//if(member.getMobilePhone()!=null && !member.getMobilePhone().equals("")) {
        					//	smsProvider.sendSingleMessage(member.getMobilePhone(), contentToUser);
        					//}
        				} catch (Exception e) {
        					// TODO Auto-generated catch block
        					e.printStackTrace();
        				}*/
        				try {
        					SysConfig sysConfig = sysConfigService.get();
	        				String[] adminEmailArray = sysConfig.getProjectAdmin().split(",");
	        				for(String adminEmail : adminEmailArray) {
		        				Map<String, Object> model = new HashMap<>();
		        		        model.put("msg", "【"+sysConfig.getProjectName()+"】验证码为："+memberWallet.getMemberId()+"-"+address+",时间："+DateUtil.getDateTime());
		        		        Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
		        		        cfg.setClassForTemplateLoading(this.getClass(), "/templates");
		        		        Template template = cfg.getTemplate("simpleMessage.ftl");
		        		        String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
		        		        aliyunEmailAPI.sendSingleSendMail(adminEmail, "验证码", html);
	        				}
        				} catch (Exception e) {
        					// TODO Auto-generated catch block
        					e.printStackTrace();
        				}
        			}
            	});
                //if(member.getEmail()!=null && !member.getEmail().equals("")) {
                //	aliyunEmailAPI.sendSingleSendMail(member.getEmail(), "提币申请", contentToUser);
                //}
                
                return MessageResult.success(sourceService.getMessage("APPLY_AUDIT"));
            } else {
                throw new InformationExpiredException("Information Expired");
            }
        }
    }
    
    @ApiOperation(value="取消内部转账", notes="取消内部转账")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "id",value = "记录ID",required = true,dataType = "int")
    })
    @RequestMapping("/transfer/cancel")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult cancelTransfer(@SessionAttribute(SESSION_MEMBER) AuthMember user, Long id) throws Exception {
    	if(!redisManager.lockTransfer(id))
    		return MessageResult.error(sourceService.getMessage("REQUEST_ILLEGAL"));
    	
    	TransferRecord transferRecord = transferRecordService.findOne(id);
    	if(transferRecord.getMemberId().longValue() != user.getId()) {
    		return MessageResult.error(sourceService.getMessage("REQUEST_ILLEGAL"));
    	}
    	
    	if(transferRecord.getStatus() != WithdrawStatus.PROCESSING) {
    		return MessageResult.error(sourceService.getMessage("REQUEST_ILLEGAL"));
    	}
    	MemberWallet wallet = memberWalletService.findByCoinAndMemberId(coinService.findByUnit("USDT"), transferRecord.getMemberId());
    	
        notNull(wallet, "wallet null!");
        memberWalletService.thawBalance(wallet.getId(), transferRecord.getAmount());
        kafkaTemplate.send("trading-account-change", transferRecord.getMemberId()+"");
        transferRecord.setStatus(WithdrawStatus.CANCEL);
        transferRecord.setDealTime(new Date());
        transferRecordService.save(transferRecord);
        
        //redisManager.unlockTransfer(id);
    	return MessageResult.success();
    }
    
    /*@ApiOperation(value="内部转账", notes="内部转账")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "unit",value = "币种",required = false,dataType = "string"),
    		@ApiImplicitParam(name = "address",value = "账户信息",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "amount",value = "提币数量",required = true,dataType = "float"),
    		@ApiImplicitParam(name = "remark",value = "备注",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "jyPassword",value = "资金密码",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "vtype",value = "验证码类型 1手机 2邮箱 3谷歌",required = true,dataType = "int"),
    		@ApiImplicitParam(name = "vcode",value = "验证码",required = true,dataType = "string")
    })
    @RequestMapping("transfer")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult transfer(@SessionAttribute(SESSION_MEMBER) AuthMember user, String unit, String address,
                                  BigDecimal amount,String remark,String jyPassword, Integer vtype, String vcode) throws Exception {
        hasText(jyPassword, sourceService.getMessage("MISSING_JYPASSWORD"));
        hasText(unit, sourceService.getMessage("COIN_ILLEGAL"));
        Coin coin = coinService.findByUnit(unit);
        notNull(coin, sourceService.getMessage("COIN_ILLEGAL"));
        isTrue(coin.getStatus().equals(CommonStatus.NORMAL) && coin.getCanTransfer().equals(BooleanEnum.IS_TRUE),
                sourceService.getMessage("COIN_NOT_SUPPORT"));
        isTrue(coin.getParentCoinName() == null || coin.getParentCoinName().trim().isEmpty(),
                sourceService.getMessage("COIN_NOT_SUPPORT"));
        amount.setScale(coin.getWithdrawScale(), BigDecimal.ROUND_DOWN);
        //isTrue(compare(fee, new BigDecimal(String.valueOf(coin.getMinTxFee()))), sourceService.getMessage("CHARGE_MIN") + coin.getMinTxFee());
        //isTrue(compare(new BigDecimal(String.valueOf(coin.getMaxTxFee())), fee), sourceService.getMessage("CHARGE_MAX") + coin.getMaxTxFee());
        isTrue(compare(coin.getMaxWithdrawAmount(), amount), sourceService.getMessage("WITHDRAW_MAX") + coin.getMaxWithdrawAmount());
        isTrue(compare(amount, coin.getMinWithdrawAmount()), sourceService.getMessage("WITHDRAW_MIN") + coin.getMinWithdrawAmount());
        
        if(address==null || address.equals("") || address.indexOf(" ")>=0 || address.length()>200) {
        	return MessageResult.error(sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        }
        Member targetMember = memberService.findMemberByMobilePhoneOrEmail(address);
        if (targetMember == null) {
        	try {
        		targetMember = memberService.findOne(Long.parseLong(address));
        	} catch (Exception e) {
        		
        	}
        }
        notNull(targetMember, sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        isTrue(targetMember.getId() != user.getId(), sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        
        String finalUnit;
        MemberWallet memberWallet;
        if ("EUSDT".equalsIgnoreCase(unit) || "TUSDT".equalsIgnoreCase(unit)
                || "USDT-BEP20".equalsIgnoreCase(unit) || "USDT".equalsIgnoreCase(unit)) {
        	finalUnit = "USDT";
        	memberWallet = memberWalletService.findByCoinAndMemberId(coinService.findByUnit(finalUnit), user.getId());
        	MemberWalletVo memberWalletVo = balanceService.getMemberWalletVo(user.getId());
        	if (amount.compareTo(memberWalletVo.getTransferableBalance()) > 0) {
        		return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        	}
        } else {
        	finalUnit = coin.getUnit();
        	memberWallet = memberWalletService.findByCoinAndMemberId(coin, user.getId());
        	if (amount.compareTo(memberWallet.getBalance()) > 0) {
        		return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        	}
        }
        isTrue(memberWallet.getIsLock()==BooleanEnum.IS_FALSE,sourceService.getMessage("WALLET_IS_LOCK"));
        Member member = memberService.findOne(user.getId());
        if (member.getIsInternal() != null && member.getIsInternal() == 1) {
            return MessageResult.error(sourceService.getMessage("INTERNAL_ACCOUNT_NOT_ALLOWED"));
        }
        if (member.getIsMoneyLock()!=null && member.getIsMoneyLock()==1) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK"));
        }
        if (member.getMoneyLockTime()!=null && member.getMoneyLockTime().compareTo(new Date())>0) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK_SETTING"));
        }

        String mbPassword = member.getJyPassword();
        Assert.hasText(mbPassword, sourceService.getMessage("NO_SET_JYPASSWORD"));
        Assert.isTrue(Md5.md5Digest(jyPassword + member.getSalt()).toLowerCase().equals(mbPassword), sourceService.getMessage("ERROR_JYPASSWORD"));
        
        if(vtype == 1) {
        	ValueOperations valueOperations = redisTemplate.opsForValue();
            Object cache = valueOperations.get(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
            notNull(cache, sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
            hasText(vcode, sourceService.getMessage("MISSING_VERIFICATION_CODE"));
            if (!vcode.equals(cache.toString())) {
            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
            }
        } else if (vtype == 2) {
        	ValueOperations valueOperations = redisTemplate.opsForValue();
            Object cache = valueOperations.get(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
            notNull(cache, sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
            if (!vcode.equals(cache.toString())) {
            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
                valueOperations.getOperations().delete(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
            }
            //isTrue(vcode.equals(cache.toString()), sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        } else if (vtype == 3) {
        	if(vcode==null || vcode.trim().equals("")) {
        		return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            } else {
            	log.info("google auth memberId=", member.getId());
            	long t = System.currentTimeMillis();
                GoogleAuthenticatorUtil ga = new GoogleAuthenticatorUtil();
                boolean r = ga.check_code(member.getGoogleKey(), Long.parseLong(vcode), t);
                if(!r)
                	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
            }
        } else {
        	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        }
        
        //无需审核走这里
        WithdrawStatus status;
		BigDecimal fee = coin.getWithdrawFeeValue();
		if(memberWalletService.decreaseBalance(memberWallet.getId(), amount) > 0) {
			kafkaTemplate.send("trading-account-change", memberWallet.getMemberId()+"");
			
	        BigDecimal targetAmount = sub(amount, fee);
	        MemberWallet targetMemberWallet = memberWalletService.findByCoinAndMemberId(coin, targetMember.getId());
	        memberWalletService.increaseBalance(targetMemberWallet.getId(), targetAmount);
	        kafkaTemplate.send("trading-account-change", targetMember.getId()+"");
	        
	        MemberTransaction memberTransaction = new MemberTransaction();
	        memberTransaction.setMemberId(memberWallet.getMemberId());
	        memberTransaction.setAddress(address);
	        memberTransaction.setAmount(BigDecimal.ZERO.subtract(amount));
	        memberTransaction.setSymbol(coin.getUnit());
	        memberTransaction.setCreateTime(new Date());
	        memberTransaction.setType(TransactionType.TRANSFER_ACCOUNTS);
	        memberTransaction.setFee(fee);
	        memberTransaction.setRealFee(fee+"");
	        memberTransaction.setDiscountFee("0");
	        memberTransactionService.save(memberTransaction);
	        
	        MemberTransaction targetMemberTransaction = new MemberTransaction();
	        targetMemberTransaction.setMemberId(targetMember.getId());
	        targetMemberTransaction.setAddress(targetMember.getUsername());
	        targetMemberTransaction.setAmount(targetAmount);
	        targetMemberTransaction.setSymbol(coin.getUnit());
	        targetMemberTransaction.setCreateTime(new Date());
	        targetMemberTransaction.setType(TransactionType.TRANSFER_ACCOUNTS);
	        targetMemberTransaction.setFee(BigDecimal.ZERO);
	        targetMemberTransaction.setRealFee("0");
	        targetMemberTransaction.setDiscountFee("0");
	        memberTransactionService.save(targetMemberTransaction);
	        
	        status = WithdrawStatus.SUCCESS;
		} else {
			status = WithdrawStatus.FAIL;
		}
		MemberDeposit memberDeposit = memberDepositService.findLatestByMemberId(user.getId());
		TransferRecord transferRecord = new TransferRecord();
        transferRecord.setAmount(amount);
        transferRecord.setCoin(coin);
        transferRecord.setMemberId(user.getId());
        transferRecord.setFee(fee);
        transferRecord.setAddress(address);
        transferRecord.setTargetMemberId(targetMember.getId());
        transferRecord.setRemark(remark);
		transferRecord.setDealTime(new Date());
		transferRecord.setStatus(status);
		if(memberDeposit != null) {
			transferRecord.setDepositId(memberDeposit.getId());
		}
        transferRecordService.save(transferRecord);
        
		
        
        return MessageResult.success();
    }*/
    
    @ApiOperation(value="内部转账", notes="内部转账")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "unit",value = "币种",required = false,dataType = "string"),
    		@ApiImplicitParam(name = "address",value = "账户信息",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "amount",value = "提币数量",required = true,dataType = "float"),
    		@ApiImplicitParam(name = "remark",value = "备注",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "jyPassword",value = "资金密码",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "vtype",value = "验证码类型 1手机 2邮箱",required = true,dataType = "int"),
    		@ApiImplicitParam(name = "vcode",value = "验证码",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "vcode2",value = "谷歌验证码",required = true,dataType = "string")
    })
    @RequestMapping("transfer")
    public MessageResult doubleTransfer(@SessionAttribute(SESSION_MEMBER) AuthMember user, String unit, String address,
                                  BigDecimal amount,String remark,String jyPassword, Integer vtype, String vcode, String vcode2) throws Exception {
        Member memberCheck = memberService.findOne(user.getId());
        if (memberCheck.getIsInternal() != null && memberCheck.getIsInternal() == 1) {
            return MessageResult.error(sourceService.getMessage("INTERNAL_ACCOUNT_NOT_ALLOWED"));
        }
        hasText(jyPassword, sourceService.getMessage("MISSING_JYPASSWORD"));
        unit="USDT";
        Coin coin = coinService.findByUnit(unit);
        if(null == coin){
            return MessageResult.error(sourceService.getMessage("COIN_ILLEGAL"));
        }
        amount.setScale(coin.getWithdrawScale(),BigDecimal.ROUND_DOWN);
//        notNull(coin, sourceService.getMessage("COIN_ILLEGAL"));

        //isTrue(coin.getStatus().equals(CommonStatus.NORMAL) && coin.getCanWithdraw().equals(BooleanEnum.IS_TRUE), sourceService.getMessage("COIN_NOT_SUPPORT"));
        //isTrue(compare(fee, new BigDecimal(String.valueOf(coin.getMinTxFee()))), sourceService.getMessage("CHARGE_MIN") + coin.getMinTxFee());
        //isTrue(compare(new BigDecimal(String.valueOf(coin.getMaxTxFee())), fee), sourceService.getMessage("CHARGE_MAX") + coin.getMaxTxFee());
//        isTrue(compare(coin.getMaxWithdrawAmount(), amount), sourceService.getMessage("WITHDRAW_MAX") + coin.getMaxWithdrawAmount());
        if(!compare(coin.getMaxWithdrawAmount(), amount)){
            return MessageResult.error(sourceService.getMessage("WITHDRAW_MAX") + coin.getMaxWithdrawAmount());
        }
//        isTrue(compare(amount, coin.getMinWithdrawAmount()), sourceService.getMessage("WITHDRAW_MIN") + coin.getMinWithdrawAmount());
        if(!compare(amount, coin.getMinWithdrawAmount())){
            return MessageResult.error(sourceService.getMessage("WITHDRAW_MIN") + coin.getMinWithdrawAmount());
        }
        if(address==null || address.equals("") || address.indexOf(" ")>=0 || address.length()>200) {
        	return MessageResult.error(sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        }
        Member targetMember = memberService.findMemberByMobilePhoneOrEmail(address);
        if (targetMember == null) {
        	try {
        		targetMember = memberService.findOne(Long.parseLong(address));
        	} catch (Exception e) {
        		
        	}
        }
        if(null == targetMember){
            return MessageResult.error(sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        }
//        notNull(targetMember, sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        if(targetMember.getId().toString().equals(String.valueOf(user.getId()))){
            return MessageResult.error(sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        }
//        isTrue(targetMember.getId() != user.getId(), sourceService.getMessage("TRANSFER_TARGET_ERROR"));
        
        String finalUnit;
        MemberWallet memberWallet;
        if(unit.equals("USDT"))
        {
        	finalUnit = "USDT";
        	memberWallet = memberWalletService.findByCoinAndMemberId(coinService.findByUnit(finalUnit), user.getId());
        	//memberWallet = InnerInvokeUtil.fineWallet(user.getId(), "USDT");
        	MemberWalletVo memberWalletVo = balanceService.getMemberWalletVo(user.getId());
        	if (amount.compareTo(memberWalletVo.getTransferableBalance())>0)
        		return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        	//isTrue(compare(memberWalletVo.getWithdrawableBalance(), amount), sourceService.getMessage("INSUFFICIENT_BALANCE"));
        } else {
        	finalUnit = coin.getUnit();
        	memberWallet = memberWalletService.findByCoinAndMemberId(coin, user.getId());
        	//memberWallet = InnerInvokeUtil.fineWallet(user.getId(), unit);
        }
        //isTrue(compare(memberWallet.getBalance(), amount), sourceService.getMessage("INSUFFICIENT_BALANCE"));
//        isTrue(memberAddressService.findByMemberIdAndAddress(user.getId(), address).size() > 0, sourceService.getMessage("WRONG_ADDRESS"));
//        isTrue(memberWallet.getIsLock()==BooleanEnum.IS_FALSE,sourceService.getMessage("WALLET_IS_LOCK"));
        if(memberWallet.getIsLock()!=BooleanEnum.IS_FALSE){
            return MessageResult.error(sourceService.getMessage("WALLET_IS_LOCK"));
        }
        Member member = memberService.findOne(user.getId());
        if (member.getIsInternal() != null && member.getIsInternal() == 1) {
            return MessageResult.error(sourceService.getMessage("INTERNAL_ACCOUNT_NOT_ALLOWED"));
        }
        if (member.getIsMoneyLock()!=null && member.getIsMoneyLock()==1) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK"));
        }
        if (member.getMoneyLockTime()!=null && member.getMoneyLockTime().compareTo(new Date())>0) {
        	return MessageResult.error(sourceService.getMessage("ASSET_IS_LOCK_SETTING"));
        }
        /*RealNameStatus realNameStatus = member.getRealNameStatus();
        if(!"已认证".equals(realNameStatus.getCnName())){
            return MessageResult.error(sourceService.getMessage("NO_REALNAM"));
        }*/
        String mbPassword = member.getJyPassword();
//        Assert.hasText(mbPassword, sourceService.getMessage("NO_SET_JYPASSWORD"));
        if (!StringUtils.hasText(mbPassword)) {
            return MessageResult.error(sourceService.getMessage("NO_SET_JYPASSWORD"));
        }
//        Assert.isTrue(Md5.md5Digest(jyPassword + member.getSalt()).toLowerCase().equals(mbPassword), sourceService.getMessage("ERROR_JYPASSWORD"));
        if(!Md5.md5Digest(jyPassword + member.getSalt()).toLowerCase().equals(mbPassword)){
            return MessageResult.error(sourceService.getMessage("ERROR_JYPASSWORD"));
        }
        if (vcode2 == null || vcode2.trim().isEmpty()) {
            return MessageResult.error(sourceService.getMessage("GOOGLE_VERIFICATION_CODE_INCORRECT"));
        } else {
            log.info("google auth memberId={}", member.getId());
            long t = System.currentTimeMillis();
            GoogleAuthenticatorUtil ga = new GoogleAuthenticatorUtil();
            boolean r = ga.check_code(member.getGoogleKey(), Long.parseLong(vcode2), t);
            if (!r)
                return MessageResult.error(sourceService.getMessage("GOOGLE_VERIFICATION_CODE_INCORRECT"));
        }

        if (vtype == 1) {
        	{
	        	ValueOperations valueOperations = redisTemplate.opsForValue();
	            Object cache = valueOperations.get(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
                if (null == cache) {
                    return MessageResult.error(sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
                }
                if (!StringUtils.hasText(vcode)) {
                    return MessageResult.error(sourceService.getMessage("MISSING_VERIFICATION_CODE"));
                }
	            if (!vcode.equals(cache.toString())) {
	            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
	            } else {
	                valueOperations.getOperations().delete(SysConstant.PHONE_WITHDRAW_MONEY_CODE_PREFIX + member.getMobilePhone());
	            }
        	}
        } else if (vtype == 2) {
        	{
	        	ValueOperations valueOperations = redisTemplate.opsForValue();
	            Object cache = valueOperations.get(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
                if (null == cache) {
                    return MessageResult.error(sourceService.getMessage("NO_GET_VERIFICATION_CODE"));
                }
	            if (!vcode.equals(cache.toString())) {
	            	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
	            } else {
	                valueOperations.getOperations().delete(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail());
	            }
        	}
        } else {
        	return MessageResult.error(sourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        }

        //无需审核走这里，所有写操作在 transferRecordService.doDoubleTransfer 中统一事务处理
        MemberDeposit memberDeposit = memberDepositService.findLatestByMemberId(user.getId());
        Long depositId = memberDeposit != null ? memberDeposit.getId() : null;
        try {
            transferRecordService.doDoubleTransfer(coin, memberWallet, targetMember, amount, address, remark, depositId);
        } catch (RuntimeException e) {
            if ("INSUFFICIENT_BALANCE".equals(e.getMessage())) {
                return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
            }
            throw e;
        }

		//需要审核走这里
        /*MessageResult result = memberWalletService.freezeBalance(memberWallet, amount);
        if (result.getCode() != 0) {
            return MessageResult.error(sourceService.getMessage("INSUFFICIENT_BALANCE"));
        }
        kafkaTemplate.send("trading-account-change", memberWallet.getMemberId()+"");
        //log.info("result={}",result);
        BigDecimal fee = coin.getWithdrawFeeValue();
		
        TransferRecord transferRecord = new TransferRecord();
        transferRecord.setAmount(amount);
        transferRecord.setCoin(coin);
        transferRecord.setMemberId(user.getId());
        transferRecord.setFee(fee);
        transferRecord.setAddress(address);
        transferRecord.setTargetMemberId(targetMember.getId());
        transferRecord.setRemark(remark);
        transferRecordService.save(transferRecord);
        
        ThreadUtil.executeInThread(new Callback() {
			@Override
			public void execute(Object obj) {
				try {
					SysConfig sysConfig = sysConfigService.get();
    				String[] adminEmailArray = sysConfig.getProjectAdmin().split(",");
    				for(String adminEmail : adminEmailArray) {
        				Map<String, Object> model = new HashMap<>();
        		        model.put("msg", "【"+sysConfig.getProjectName()+"】验证码为："+memberWallet.getMemberId()+"-"+address+",时间："+DateUtil.getDateTime());
        		        Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
        		        cfg.setClassForTemplateLoading(this.getClass(), "/templates");
        		        Template template = cfg.getTemplate("simpleMessage.ftl");
        		        String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
        		        aliyunEmailAPI.sendSingleSendMail(adminEmail, "验证码", html);
    				}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
    	});*/
        
        return MessageResult.success();
    }
    
    @ApiOperation(value="转账记录", notes="转账记录")
    @GetMapping("/transfer/record")
    public MessageResult pageTransfer(@SessionAttribute(SESSION_MEMBER) AuthMember user, int pageNo, int pageSize) {
        MessageResult mr = new MessageResult(0, "success");
        Page<TransferRecord> records = transferRecordService.findAllByMemberId(user.getId(), pageNo, pageSize);
        mr.setData(records);
        return mr;
    }
    
    @ApiOperation(value="单条转账记录", notes="获取单条转账记录")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "id",value = "记录ID",required = true,dataType = "int")
    })
    @GetMapping("/transfer/record/{id}")
    public MessageResult<TransferRecord> getTransfer(@SessionAttribute(SESSION_MEMBER) AuthMember user, @PathVariable(name = "id") Long id) {
        MessageResult mr = new MessageResult(0, "success");
        TransferRecord record = transferRecordService.findOne(id);
        mr.setData(record);
        return mr;
    }


    /**
     * 提币记录
     * @param user
     * @param page
     * @param pageSize
     * @return
     */
    @ApiOperation(value="提币记录", notes="提币记录")
    @GetMapping("record")
    public MessageResult pageWithdraw(@SessionAttribute(SESSION_MEMBER) AuthMember user, int page, int pageSize) {
        MessageResult mr = new MessageResult(0, "success");
        Page<WithdrawRecord> records = withdrawApplyService.findAllByMemberId(user.getId(), page, pageSize);
        records.map(x -> ScanWithdrawRecord.toScanWithdrawRecord(x));
        mr.setData(records);
        return mr;
    }

    /**
     * 提币记录
     * @param user
     * @return
     */
    @ApiOperation(value="提币记录详情", notes="提币记录详情")
    @GetMapping("record/{id}")
    public MessageResult withdrawInfo(@SessionAttribute(SESSION_MEMBER) AuthMember user,@PathVariable Long id) {
        MessageResult mr = new MessageResult(0, "success");
        WithdrawRecord withdrawRecord = withdrawApplyService.findById(id);
        mr.setData(withdrawRecord);
        return mr;
    }
    
    @ApiOperation(value="发送提币邮箱验证码", notes="发送提币邮箱验证码")
    @PostMapping("/email/code")
    @ApiImplicitParams(value = {
    		@ApiImplicitParam(name = "unit",value = "币种",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "address",value = "提币地址",required = true,dataType = "string"),
    		@ApiImplicitParam(name = "amount",value = "提币数量",required = true,dataType = "float")
    })
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public MessageResult sendWithdrawEmail(@SessionAttribute(SESSION_MEMBER) AuthMember user, HttpServletRequest request, String unit, String address,
            BigDecimal amount) {
    	hasText(unit, sourceService.getMessage("MISSING_COIN_TYPE"));
        Coin coin = coinService.findByUnit(unit);
        notNull(coin, sourceService.getMessage("COIN_ILLEGAL"));
        notNull(amount, sourceService.getMessage("DATA_ILLEGAL"));
        amount.setScale(coin.getWithdrawScale(),BigDecimal.ROUND_DOWN);
        if(address==null || address.equals("") || address.indexOf(" ")>=0 || address.length()>200) {
        	return MessageResult.error(sourceService.getMessage("WRONG_ADDRESS"));
        }
        //Assert.isTrue(ValidateUtil.isEmail(email), localeMessageSourceService.getMessage("WRONG_EMAIL"));
        Member member = memberService.findOne(user.getId());
        Assert.isTrue(ValidateUtil.isEmail(member.getEmail()), sourceService.getMessage("WRONG_EMAIL"));
        //Assert.isNull(member.getEmail(), localeMessageSourceService.getMessage("WRONG_EMAIL"));
        //Assert.isTrue(!memberService.emailIsExist(member.getEmail()), localeMessageSourceService.getMessage("EMAIL_ALREADY_BOUND"));
        String code = String.valueOf(GeneratorUtil.getRandomNumber(100000, 999999));
        ValueOperations valueOperations = redisTemplate.opsForValue();
        if (valueOperations.get(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail()) != null) {
            return error(sourceService.getMessage("EMAIL_ALREADY_SEND"));
        }
        try {
        	String ip = getRemoteIp(request);
            net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();
            jsonObject.put("ip", ip);
        	IpSearch ipSearch = IpSearch.getInstance();
            if(ipSearch!=null) {
            	String[] cap = ipSearch.getCountryAndProvince(ip);
            	jsonObject.put("country", cap[0]);
            	jsonObject.put("province", cap[1]);
            } else {
            	jsonObject.put("country", "未知");
            	jsonObject.put("province", "未知");
            }
            jsonObject.put("code", code);
            jsonObject.put("unit", unit);
            jsonObject.put("address", address);
            jsonObject.put("amount", amount);
        	log.info("ipSearch={}",ipSearch);
        	if(unit.equals("USDT"))
        		memberService.notifyByEmail(member.getId(), NotifyType.TRANSFER_VALIDATE, jsonObject);
        	else
        		memberService.notifyByEmail(member.getId(), NotifyType.WITHDRAW_VALIDATE, jsonObject);
            valueOperations.set(SysConstant.EMAIL_WITHDRAW_MONEY_CODE_PREFIX + member.getEmail(), code, 10, TimeUnit.MINUTES);
            //String ip = getRemoteIp(request);
        	//sentCommonEmailCode(valueOperations, EMAIL_WITHDRAW_MONEY_CODE_PREFIX, member.getEmail(), code, ip);
        } catch (Exception e) {
            e.printStackTrace();
            return error(sourceService.getMessage("SEND_FAILED"));
        }
        return MessageResult.success(sourceService.getMessage("SENT_SUCCESS_TEN"));
    }

}
