<?php
require_once mvc::$cfg['AUTOLOAD']['Main']['path']."WxpayAPI_php_v3/WxPay.Base.php";
/**
  * @method 订单
  * @author soul
  * @copyright 2016/3/31
  */
class MainOrder extends MainBase
{
	/**
	  * @method 创建并生成支付订单
	  * @param  dataArr               array  [必填] [
														'por_guid'=>[必填]32位长度的唯一编码GUID,
														'por_u_id'=>[必填]宜配会员ID,
														'por_style'=>[必填] 业务标识  PJLCZ:跑街令充值  PJLVIP:跑街令VIP  PJLPAC:跑街令资源包 PJLORD:跑街令订单 PJDORD:商城订单  YPING:宜配网积分  QIPERIS:汽配搜,
														'por_from'=> YP(宜配网)|YPAPP|YPGZG|YPIM|YPYPC|PJD(跑街的)|PJDAPP|PJDZS(跑街的助手)|PJDGZH|PJDSGZH(商城店铺公众号)|PJL(跑街令)|CRM|BMTSR|CLIENT(客户网)
														'por_pay_method'=>[可选]weixin微信(默认) alipay支付宝
														'por_pay_type'=>[可选]pc:扫码(默认)  app:APP  wap:手机网 gzh:公众号
														'por_orderids'=>[可选]来源的订单ID,
														'por_money'=>[必填]'10.56',
														'por_title'=>[必填]'宜配网-积分充值订单：121245',
														'por_back_url'=>[可选]成功后的回调链接,
														'por_wx_openid'=>[可选]gzh:公众号支付需要提供,
													];
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['por_id'=>xxxx, 'por_return_data'=>'二维码链接'....]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function buildPay($dataArr)
	{
		//过滤数据
		$filedArr = ['por_guid', 'por_u_id', 'por_from', 'por_pay_method', 'por_pay_type', 'por_style', 'por_orderids', 'por_money', 'por_title', 'por_des', 'por_back_url', 'por_wx_openid'];
		foreach($dataArr as $filed=>$val)
		{
			if(!in_array($filed, $filedArr))
			{
				unset($dataArr[$filed]);
				continue;
			}
		}

		//判断具体的参数
		$mustArr = ['por_guid', 'por_u_id', 'por_money', 'por_title', 'por_style'];
		foreach($mustArr as $filed)
		{
			if(!isset($dataArr[$filed]))
			{
				return LibFc::ReturnData(false, $filed.'参数必填，创建支付订单失败！');
			}
		}

		$dataArr['por_money'] = sprintf("%.2f", $dataArr['por_money']);
		if($dataArr['por_money'] < 0.01)
			return LibFc::ReturnData(false, 'por_money金额必须大于0元，创建支付订单失败！');
		
		//默认值
		$dataArr['por_pay_method'] = !empty($dataArr['por_pay_method']) && $dataArr['por_pay_method'] == 'alipay'? 'alipay': 'weixin';
		
		$res = $this->get('cm_xiangmu', ['xim_acc_code'], sprintf(" and xim_code='%s' limit 1", LibFc::Escape($dataArr['por_style'])), true);
		if(empty($res['data'])) return LibFc::ReturnData(false, '业务标识por_style：'.$dataArr['por_style'].'不存在，创建支付订单失败！');
		$dataArr['por_account'] = $res['data']['xim_acc_code'];
		
		if($dataArr['por_account'] == 'YP' && $dataArr['por_pay_method'] == 'alipay')
			return LibFc::ReturnData(false, '此业务尚未开通支付宝支付，创建支付订单失败！');


		$dataArr['por_from'] = empty($dataArr['por_from'])? 'YP': $dataArr['por_from'];
		$dataArr['por_pay_type'] = empty($dataArr['por_pay_type'])? 'pc': $dataArr['por_pay_type'];
		$dataArr['por_atime'] = time();
		
		if($dataArr['por_pay_method'] == 'weixin' && $dataArr['por_pay_type'] == 'gzh' && empty($dataArr['por_wx_openid']))
			return LibFc::ReturnData(false, 'por_wx_openid参数必填，创建支付订单失败！');

		//检查GUID
		if(!preg_match('/[0-9a-zA-Z]{32}/', $dataArr['por_guid']))
			return LibFc::ReturnData(false, 'por_guid不符合规则，创建支付订单失败！');
		
		$res = $this->get('pa_order', ['por_id', 'por_money', 'por_pay_method', 'por_pay_type', 'por_u_id', 'por_title'], sprintf(" and por_guid='%s'", $dataArr['por_guid']), true);
		if(!empty($res['data']))
		{
			foreach($res['data'] as $k=>$v)
			{
				if($dataArr[$k] != $v)
				{
					return LibFc::ReturnData(false, $k.'发生变化，por_guid已被使用，创建支付订单失败！');
				}
			}
			return $this->getPayPage($res['data']['por_id']);
		}
		$this->MainDb->Begin();
		$res = $this->add('pa_order', $dataArr);
		
		$res = $this->getPayPage($res['data']);
		$this->MainDb->End();
		return $res;
	}


	/**
	  * @method 根据订单ID获取对应的支付信息
	  * @param  proId  支付订单ID
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['por_id'=>xxxx, 'por_return_data'=>'二维码链接'...]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function getPayPage($proId)
	{
		$proId = (int) $proId;
		$filedArr = ['por_id', 'por_guid', 'por_u_id', 'por_account', 'por_status', 'por_pay_method', 'por_pay_type', 'por_trade_no', 'por_orderids', 'por_money', 'por_title', 'por_pay_time', 'por_return_data', 'por_return_etime', 'por_back_url', 'por_wx_openid'];
		$res = $this->get('pa_order', $filedArr, sprintf(" and por_id=%d", $proId), true);
		$dataArr = $res['data'];
		$accountTag = $dataArr['por_account'];
		if(empty($dataArr)) return LibFc::ReturnData(false, '提供的支付订单proId不存在');

		if($dataArr['por_status'] == 1)
			return LibFc::ReturnData(false, '此支付单已支付，请勿重复支付', 'ORDERPAID');

		if($dataArr['por_status'] != 0)
			return LibFc::ReturnData(false, '此支付单已关闭', 'CLOSED');
		
		//已经生成过并且数据未过期
		if($dataArr['por_status'] == 0 && !empty($dataArr['por_return_data']) && $dataArr['por_return_etime'] > time() )
		{
			$dataArr['por_return_data'] = json_decode($dataArr['por_return_data']);
			return LibFc::ReturnData(true, $dataArr);
		}

		if($dataArr['por_pay_method'] == 'weixin')
		{
			//处理之前生成的链接，微信
			if(!empty($dataArr['por_trade_no']))
			{
				$res = $this->getWxPayOrder($accountTag, $resArr['por_trade_no'], 'out_trade_no');
				if(!empty($res['data']['por_status']) && $res['data']['por_status'] == 1)
					return LibFc::ReturnData(false, '此支付单已支付，请勿重复支付', 'ORDERPAID');
				
				//关闭之前的
				$this->closeWxPay($accountTag, $dataArr['por_trade_no']);
				$dataArr['por_return_etime'] = 0;
			}
			
			//公众号支付特殊处理 openid 和 APPID 必须保持一致
			if($accountTag == 'PJL' && $dataArr['por_pay_type'] == 'gzh' && !empty($dataArr['por_wx_openid']))
				mvc::$cfg['PAY']['WX']['PJL']['APPID'] = mvc::$cfg['PAY']['WX']['YP']['APPID'];
			
			$WxPayApi = new WxPayApi($accountTag);
			$WxPay = new WxPayUnifiedOrder($accountTag);

			$dataArr['por_trade_no'] = $dataArr['por_id'].'_'.time();
			$dataArr['por_return_etime'] = time() + 3600;
			$WxPay->SetBody($dataArr['por_title']);
			$WxPay->SetOut_trade_no($dataArr['por_trade_no']);
			$WxPay->SetProduct_id($dataArr['por_id']);
			$WxPay->SetTotal_fee($dataArr['por_money']*100);
			$WxPay->SetTime_start(date("YmdHis"));
			$WxPay->SetTime_expire(date("YmdHis", $dataArr['por_return_etime']));
			$WxPay->SetNotify_url(mvc::$cfg['urls']['notifyWX']);
			
			switch($dataArr['por_pay_type'])
			{
				case 'wap':
					$WxPay->SetTrade_type("MWEB");
					$result = $WxPayApi->unifiedOrder($WxPay);
					if($result['return_code'] == 'SUCCESS')
					{
						if(empty($result['mweb_url']))
							return LibFc::ReturnData(false, $result['err_code_des'], $result['err_code']);
						$dataArr['por_return_data'] = json_encode(['pay_url'=> $result['mweb_url']]);
					}
					else
					{
						return LibFc::ReturnData(false, $result['return_msg'], 'SYSTEM');
					}
				break;
				case 'pc':
					$WxPay->SetTrade_type("NATIVE");
					$result = $WxPayApi->unifiedOrder($WxPay);
					if($result['return_code'] == 'SUCCESS')
					{
						if(empty($result['code_url']))
							return LibFc::ReturnData(false, $result['err_code_des'], $result['err_code']);
						$dataArr['por_return_data'] = json_encode(['pay_url'=> mvc::$cfg['urls']['b2c'].'qrcode.php?data='.urlencode($result['code_url'])]);
					}
					else
					{
						return LibFc::ReturnData(false, $result['return_msg'], 'SYSTEM');
					}
				break;
				case 'gzh':
					$WxPay->SetTrade_type("JSAPI");
					$WxPay->SetOpenid($dataArr['por_wx_openid']);
					$result = $WxPayApi->unifiedOrder($WxPay);
					if($result['return_code'] == 'SUCCESS')
					{
						if($result['result_code'] != 'SUCCESS')
							return LibFc::ReturnData(false, $result['err_code_des'], $result['err_code']);

						if(!array_key_exists("appid", $result) || !array_key_exists("prepay_id", $result) || $result['prepay_id'] == "")
							return LibFc::ReturnData(false, '生成JsApiPay参数错误');
						
						$jsapi = new WxPayJsApiPay($accountTag);
						$jsapi->SetAppid($result["appid"]);
						$jsapi->SetTimeStamp((string) time());
						$jsapi->SetNonceStr($WxPayApi->getNonceStr());
						$jsapi->SetPackage("prepay_id=" . $result['prepay_id']);
						$jsapi->SetSignType("MD5");
						$jsapi->SetPaySign($jsapi->MakeSign());
						$dataArr['por_return_data'] = json_encode($jsapi->GetValues());
					}
					else
					{
						return LibFc::ReturnData(false, $result['return_msg'], 'SYSTEM');
					}
				break;
				case 'app':
					$WxPay->SetTrade_type("APP");
					$result = $WxPayApi->unifiedOrder($WxPay);
					if($result['return_code'] == 'SUCCESS')
					{
						if(empty($result['prepay_id']))
							return LibFc::ReturnData(false, $result['err_code_des'], $result['err_code']);
						//重新生成签名
						$result['timestamp'] = (string) time();
						$result['package'] = 'Sign=WXPay';
						$signArr = [
							'appid'=>$result['appid'],
							'partnerid'=>$result['mch_id'],
							'prepayid'=>$result['prepay_id'],
							'noncestr'=>$result['nonce_str'],
							'timestamp'=>$result['timestamp'],
							'package'=>$result['package']
						];

						$WxPayDataBase = new WxPayDataBase($accountTag);
						$WxPayDataBase->values = $signArr;
						$result['sign'] = $WxPayDataBase->MakeSign();
						$dataArr['por_return_data'] = json_encode($result);
					}
					else
					{
						return LibFc::ReturnData(false, $result['return_msg'], 'SYSTEM');
					}
				break;
			}
			
		}
		else if($dataArr['por_pay_method'] == 'alipay')
		{
			//支付宝
			if(!empty($dataArr['por_trade_no']))
			{
				$MainAliPay = new MainAliPay();
				$res = $MainAliPay->getAliPayOrder($dataArr['por_trade_no'], 'out_trade_no');
				if(!empty($res['data']['por_status']) && $res['data']['por_status'] == 1)
					return LibFc::ReturnData(false, '此支付单已支付，请勿重复支付', 'ORDERPAID');

				$MainAliPay->closeAliPay($dataArr['por_trade_no']);
				$dataArr['por_return_etime'] = 0;
			}

			$dataArr['por_trade_no'] = $dataArr['por_id'].'_'.time();
			$dataArr['por_return_etime'] = time() + 3600;
			$MainAliPay = new MainAliPay();
			switch($dataArr['por_pay_type'])
			{
				case 'app':
					$othAliArr = ['setNotifyUrl'=>mvc::$cfg['urls']['notifyAli']];
					$bizArr = [
						'body'=>$dataArr['por_title'],
						'subject'=>$dataArr['por_title'],
						'out_trade_no'=>$dataArr['por_trade_no'],
						'timeout_express'=>'30m',
						'total_amount'=>$dataArr['por_money'],
						'product_code'=>'QUICK_MSECURITY_PAY',	
					];
					$res = $MainAliPay->getApi('AlipayTradeAppPayRequest', $bizArr, $othAliArr);
				break;
				default:
					$bizArr = [
						'product_code'=>'FAST_INSTANT_TRADE_PAY',	
						'out_trade_no'=>$dataArr['por_trade_no'],
						'total_amount'=>$dataArr['por_money'],
						'subject'=>$dataArr['por_title'],
						'body'=>$dataArr['por_title']
					];
					$othAliArr = [
						'setReturnUrl'=>$dataArr['por_back_url'],
						'setNotifyUrl'=>mvc::$cfg['urls']['notifyAli']
					];
					$res = $MainAliPay->getApi('AlipayTradePagePayRequest', $bizArr, $othAliArr);
				break;
			}
			$dataArr['por_return_data'] = json_encode($res['data']);
		}
		$this->set('pa_order', $dataArr, sprintf(" AND por_id=%d", $dataArr['por_id']));
		$dataArr['por_return_data'] = json_decode($dataArr['por_return_data']);
		return LibFc::ReturnData(true, $dataArr);
	}

	
	/**
	  * @method 重新获取支付状态
	  * @param  $id ID值
	  * @param  $type por_id || por_guid
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['por_id'=>, 'por_status'=>, 'por_pay_time'=>]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function checkPay($id, $type = 'por_id')
	{
		$arr = [];
		$where = $type == 'por_guid' ? sprintf(" AND por_guid='%s'",  LibFc::Escape($id)): sprintf(" AND por_id=%d",  $id);
		$returnFiledArr = ['por_id', 'por_guid', 'por_status', 'por_style', 'por_orderids', 'por_pay_method', 'por_title', 'por_trade_no','por_pay_time', 'por_transaction_id', 'por_money', 'por_account'];
		$res = $this->get('pa_order', $returnFiledArr, $where, true);
		$arr = $res['data'];
		if(!empty($arr) && $arr['por_status'] == 0 && !empty($arr['por_trade_no']))
		{
			switch($arr['por_pay_method'])
			{
				case 'weixin':
					$result = $this->getWxPayOrder($arr['por_account'], $arr['por_trade_no'], 'out_trade_no');
					$result = $result['data'];
					if(!empty($result['por_status']) && $result['por_status'] == 1)
					{
						$res = $this->get('pa_order', $returnFiledArr, sprintf(" and por_id=%d", $arr['por_id']), true);
						$arr = $res['data'];
						if(!empty($arr['por_back_url']))
						{
							$LibCurl = new LibCurl(false,false);
							$LibCurl->timeout = 1;
							$LibCurl->fetch($arr['por_back_url'].'?por_guid='.$arr['por_guid']);
						}
					}
				break;
				case 'alipay':
					$MainAliPay = new MainAliPay();
					$result = $MainAliPay->getAliPayOrder($arr['por_trade_no'], 'out_trade_no');
					$result = $result['data'];
					
					if(!empty($result['por_status']) && $result['por_status'] == 1)
					{
						$res = $this->get('pa_order', $returnFiledArr, sprintf(" and por_id=%d", $arr['por_id']), true);
						$arr = $res['data'];
						if(!empty($arr['por_back_url']))
						{
							$LibCurl = new LibCurl(false,false);
							$LibCurl->timeout = 1;
							$LibCurl->fetch($arr['por_back_url'].'?por_guid='.$arr['por_guid']);
						}
					}
				break;
			}
		}
		return LibFc::ReturnData(true, $arr);
	}

	/**
	  * @method 关闭支付订单
	  * @param  $porId int|array   支付订单ID
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['por_id'=>, 'por_status'=>, 'por_pay_time'=>]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function closePay($porId)
	{
		if(empty($porId)) return LibFc::ReturnData(false, '提供的porId不正确');

		$porIdArr = is_array($porId)? $porId: [$porId];
		foreach($porIdArr as $k=>$v)
		{
			$porIdArr[$k] = (int) $v;
		}
		if(empty($porIdArr)) return LibFc::ReturnData(false, '提供的porId不正确');
			
		$res = $this->get('pa_order', ['por_id', 'por_status', 'por_trade_no', 'por_pay_method', 'por_account'], sprintf(" and por_id IN (%s)", implode(',', $porIdArr)));
		$porArr = $res['data'];
		$this->MainDb->Begin();
		foreach($porArr as $por)
		{
			$resArr[$por['por_id']] = $por['por_status'];
			if($por['por_status'] == 1)
			{
				return LibFc::ReturnData(false, 'porId:'.$por['por_id'].'支付已完成，关闭失败');
			}
			if(!empty($por['por_trade_no']))
			{
				switch($por['por_pay_method'])
				{
					case 'weixin': 
						$this->closeWxPay($por['por_account'], $por['por_trade_no']);
						$resArr[$por['por_id']] = -1;
					break;
					case 'alipay':
						$MainAliPay = new MainAliPay();
						$MainAliPay->closeAliPay($por['por_trade_no']);
						$resArr[$por['por_id']] = -1;
					break;
				}
				$this->set('pa_order', ['por_status'=>-1], sprintf(" and por_id=%d", $por['por_id']));
			}
		}
		$this->MainDb->End();
		return LibFc::ReturnData(true, $resArr);
	}


	

	

	/**
	  * @method 申请退款【已完成支付的订单申请退款，需要关闭之前的未完成的退款再申请】
	  * @param  dataArr               array         [
														'pre_por_id'=>宜配支付中心订单ID,
														'pre_refund_money'=>1.02,
														'pre_des'=>''
													];
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['pre_id'=>xxxx, 'err_code'=>'', 'err_msg'=>''....]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function refund($dataArr)
	{
		$mustArr = ['pre_por_id', 'pre_guid', 'pre_refund_money'];
		foreach($mustArr as $filed)
		{
			if(!isset($dataArr[$filed]))
				return LibFc::ReturnData(false, $filed.'参数必填');
		}
		$dataArr['pre_refund_money'] = sprintf("%.2f", $dataArr['pre_refund_money']);
		$dataArr['pre_por_id'] = (int) $dataArr['pre_por_id'];
		if(!preg_match('/[0-9a-zA-Z]{32}/', $dataArr['pre_guid']))
			return LibFc::ReturnData(false, '提供的pre_guid不符合规则');

		$res = $this->get('pa_order', ['por_id', 'por_status', 'por_trade_no', 'por_money', 'por_pay_method', 'por_account'], sprintf(" and por_id=%d", $dataArr['pre_por_id']), true);
		$payOrderArr = $res['data'];
		if(empty($payOrderArr) || $payOrderArr['por_status'] != 1)
			return LibFc::ReturnData(false, '支付订单不存在或者尚未完成支付');

		$accountTag = $payOrderArr['por_account'];

		//同一笔交易 多次申请退款必须间隔10s
		$res = $this->get('pa_refund', ['max(pre_atime) as pre_atime'], sprintf(" and pre_por_id=%d and pre_status != -1", $dataArr['pre_por_id']), true);
		$waitTime = time()-$res['data']['pre_atime'];
		if($waitTime < 10)
			return LibFc::ReturnData(false, '退款频率过快，请'.$waitTime.'秒后重试');
		
		$res = $this->get('pa_refund', ['pre_id'], sprintf(" and pre_status=0 and pre_por_id=%d", $dataArr['pre_por_id']), true);
		if(!empty($res['data']))
		{
			$this->getRefund($res['data']['pre_id'], 'pre_id');
			$res = $this->get('pa_refund', ['pre_id'], sprintf(" and pre_status=0 and pre_por_id=%d", $dataArr['pre_por_id']), true);
			if(!empty($res['data']))
				return LibFc::ReturnData(false, '此支付订单有一笔退款尚未完成，请稍后再申请。');
		}

		unset($dataArr['pre_status']);
		unset($dataArr['pre_out_refund_no']);
		unset($dataArr['pre_refund_id']);
		unset($dataArr['pre_refund_json']);
		
		$res = $this->get('pa_refund', ['*'], sprintf(" and pre_guid='%s'", $dataArr['pre_guid']), true);
		if(!empty($res['data']))
		{
			if($res['data']['pre_refund_money'] != $dataArr['pre_refund_money'] || $res['data']['pre_por_id'] != $dataArr['pre_por_id'])
				return LibFc::ReturnData(false, '提供的pre_guid已被使用');
			//已经存在
			$dataArr = $res['data'];
			//检测退款信息
			$this->getRefund($dataArr['pre_id'], 'pre_id');
			return LibFc::ReturnData(true, $dataArr['pre_id']);
		}
		
		//创建新的商户订单号
		$dataArr['pre_out_refund_no'] = $payOrderArr['por_id'].'_T'.time();
		$dataArr['pre_atime'] = time();
		$this->MainDb->Begin();
		$res = $this->add('pa_refund', $dataArr);
		$dataArr['pre_id'] = $res['data'];
		$errArr = ['flag'=>false, 'msg'=>''];
		switch($payOrderArr['por_pay_method'])
		{
			case 'weixin':
				$input = new WxPayRefund($accountTag);
				$WxPayApi = new WxPayApi($accountTag);
				$input->SetOut_trade_no($payOrderArr['por_trade_no']);
				$input->SetTotal_fee($payOrderArr['por_money']*100);
				$input->SetRefund_fee($dataArr['pre_refund_money']*100);
				$input->SetOut_refund_no($dataArr['pre_out_refund_no']);
				$input->SetOp_user_id($input->MCHID);
				$result = $WxPayApi->refund($input);
				if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS')
				{
					$this->set('pa_refund', ['pre_refund_id'=>$result['refund_id']], sprintf(" AND pre_id=%d", $dataArr['pre_id']));
				}
				else if($result['return_code'] == 'SUCCESS')
				{
					$errArr = ['flag'=>true, 'msg'=>$result['err_code_des']];
				}
				else
				{
					$errArr = ['flag'=>true, 'msg'=>$result['return_msg']];
				}
			break;
			case 'alipay':
				$MainAliPay = new MainAliPay();
				$bizArr = [
					'out_trade_no'=>$payOrderArr['por_trade_no'],
					'refund_amount'=>$dataArr['pre_refund_money'],
					'out_request_no'=>$dataArr['pre_out_refund_no']
				];
				$res = $MainAliPay->getApi('AlipayTradeRefundRequest', $bizArr);
				$result = $res['data'];
				$this->set('pa_refund', ['pre_refund_json'=>json_encode($result)], sprintf(" AND pre_id=%d", $dataArr['pre_id']));
				
			break;
		}
		if($errArr['flag'])
		{
			$this->set('pa_refund', ['pre_status'=>-1], sprintf(" AND pre_id=%d", $dataArr['pre_id']));
			$this->MainDb->End();
			$this->getRefund($dataArr['pre_id'], 'pre_id');
			return LibFc::ReturnData(false, $errArr['msg']);
		}
		$this->MainDb->End();
		$this->getRefund($dataArr['pre_id'], 'pre_id');
		return LibFc::ReturnData(true, $dataArr['pre_id']);
	}


	/**
	  * @method 查询退款
	  * @param  $val ID值
	  * @param  $type pre_id || pre_guid
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['pre_id'=>xxxx, 'pre_por_id'=>'', 'pre_status'=>''....]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function getRefund($val, $type= 'pre_id')
	{
		$where = $type== 'pre_id'? sprintf(" AND pre_id=%d", $val): sprintf(" AND pre_guid='%s'", $val);
		$filedArr = ['pre_id', 'pre_guid', 'pre_por_id', 'pre_status', 'pre_refund_money', 'por_trade_no','pre_out_refund_no', 'pre_refund_id', 'pre_atime', 'pre_refund_time', 'por_pay_method', 'por_account', 'por_money'];
		$res = $this->get('pa_refund JOIN pa_order ON por_id=pre_por_id', $filedArr, $where, true);
		if(empty($res['data']))
		{
			return LibFc::ReturnData(false, 'getRefund 退款单不存在');
		}

		$refundArr = $res['data'];
		if($refundArr['pre_status'] == 0)
		{
			$accountTag = $refundArr['por_account'];
			$preId = $refundArr['pre_id'];
			switch($refundArr['por_pay_method'])
			{
				case 'weixin':
					$input = new WxPayRefundQuery($accountTag);
					$WxPayApi = new WxPayApi($accountTag);
					$input->SetOut_refund_no($refundArr['pre_out_refund_no']);
					$result = $WxPayApi->refundQuery($input);
					
					if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS')
					{
						if($result['refund_status_0'] == 'SUCCESS')
						{
							$refundArr['pre_status'] = 1;
							$this->set('pa_refund', ['pre_status'=>$refundArr['pre_status'], 'pre_refund_json'=>json_encode($result), 'pre_refund_time'=>strtotime($result['refund_success_time_0'])], sprintf(" AND pre_id=%d", $preId));
						}
						else if($result['refund_status_0'] == 'REFUNDCLOSE')
						{
							$refundArr['pre_status'] = -1;
							$this->set('pa_refund', ['pre_status'=>$refundArr['pre_status'], 'pre_refund_json'=>json_encode($result)], sprintf(" AND pre_id=%d", $preId));
						}
						
					}
					else if($result['return_code'] == 'SUCCESS')
					{
						return LibFc::ReturnData(false, $result['err_code_des']);
					}
					else
					{
						return LibFc::ReturnData(false, $result['return_msg']);
					}
				break;
				case 'alipay':
					$MainAliPay = new MainAliPay();
					$bizArr = [
						'out_trade_no'=>$refundArr['por_trade_no'],
						'out_request_no'=>$refundArr['pre_out_refund_no']
					];
					$res = $MainAliPay->getApi('AlipayTradeFastpayRefundQueryRequest', $bizArr);
					$result = $res['data'];
					if(!empty($result['trade_no']))
					{
						$setArr = [
							'pre_status'=>1,
							'pre_refund_id'=>$result['trade_no'],
							'pre_refund_time'=>$refundArr['pre_atime'],
							'pre_refund_json'=>json_encode($result)
						];
						$this->set('pa_refund', $setArr, sprintf(" AND pre_id=%d", $preId));
					}
					/*接口并没有返回文档的数据信息
					if($result['refund_status'] == 'REFUND_SUCCESS')
					{
						$refundArr['pre_status'] = 1;
						$this->set('pa_refund', ['pre_status'=>$refundArr['pre_status'], 'pre_refund_json'=>json_encode($result), 'pre_refund_time'=>time()], sprintf(" AND pre_id=%d", $preId));
					}
					else if($result['refund_status'] == 'REFUND_FAIL')
					{
						$refundArr['pre_status'] = -1;
						$this->set('pa_refund', ['pre_status'=>$refundArr['pre_status'], 'pre_refund_json'=>json_encode($result)], sprintf(" AND pre_id=%d", $preId));
					}*/
					
				break;
			}
		}
		return LibFc::ReturnData(true, $refundArr);
	}

	

	/**
	  * @method 企业付款
	  * @param  dataArr               array  [必填] 1、已有订单ID['pmc_id'=>xxx, .....]
										            2、需要新建 [
														'pmc_u_id'=>宜配会员ID,
														'pmc_from'=>'主站'|'B2C',
														'pmc_style'=>PJLSHARE:邀请赚钱提现 PJLYETX:跑街令余额提现
														'pmc_orderid'=>请求者的订单ID
														'pmc_to_openid'=>收款账号的唯一码
														'pmc_to_name'=>收款人姓名,
														'pmc_to_idcard'=>收款人身份证,
														'pmc_pay_by'=>'weixin',
														'pmc_money'=>'10.56',
														'pmc_des'=>'提现订单：121245'
													];
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['pmc_u_id', 'err_msg'=>''....]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function mchPay($dataArr)
	{
		unset($dataArr['pmc_status']);
		unset($dataArr['pmc_payment_no']);
		unset($dataArr['pmc_partner_trade_no']);
		if(isset($dataArr['pmc_money']))
		{
			$dataArr['pmc_money'] = sprintf("%.2f", $dataArr['pmc_money']);
		}
	
		$filedArr = ['*'];
		//已有支付订单
		if(!empty($dataArr['pmc_id']))
		{
			//判断是否修改GUID
			if(isset($dataArr['pmc_guid']))
			{
				if(preg_match('/[0-9a-zA-Z]{32}/', $dataArr['pmc_guid']))
				{
					$res = $this->get('pa_mchpay', ['pmc_id'], sprintf(" and pmc_guid='%s' and pmc_id!=%d", $dataArr['pmc_guid'], $dataArr['pmc_id']), true);
					if(!empty($res['data'])) return LibFc::ReturnData(false, '提供的pmc_guid已被使用');
				}
				else
				{
					return LibFc::ReturnData(false, '提供的pmc_guid不符合规则');
				}
			}

			$res = $this->get('pa_mchpay', $filedArr, sprintf(" and pmc_id=%d", $dataArr['pmc_id']), true);
			$dataArr = $res['data'];
			if(empty($dataArr))
			{
				return LibFc::ReturnData(true, ['err_code'=>'NOORDER', 'err_msg'=>'企业付款订单不存在']);
			}
			else if($dataArr['pmc_status'] == 1)
			{
				$dataArr['err_code'] = 'ORDERPAID';
				$dataArr['err_msg'] = '企业付款订单已付款，请勿重复操作';
				return LibFc::ReturnData(true, $dataArr);
			}
			else if($dataArr['pmc_status'] != 0)
			{
				return LibFc::ReturnData(true, ['err_code'=>'CLOSED', 'err_msg'=>'企业付款订单已关闭']);
			}
			
			if(!empty($dataArr['pmc_partner_trade_no']))
			{
				switch($dataArr['pmc_pay_by'])
				{
					case 'weixin':
						return $this->getMchPay($dataArr['pmc_id']);
					break;
				}
			}
		}

		$this->MainDb->Begin();
		if(empty($dataArr['pmc_id']))
		{
			$res = $this->get('pa_mchpay', ['pmc_atime'], sprintf(" AND pmc_to_openid='%s' ORDER BY pmc_atime DESC LIMIT 1", LibFc::Escape($dataArr['pmc_to_openid'])), true);
			if(!empty($res['data']['pmc_atime']) && ($res['data']['pmc_atime'] +30) > time())
			{
				return LibFc::ReturnData(false, '同一个收款人，两次转账时间间隔不得低于30秒');
			}
			
			//新建订单
			$mustArr = ['pmc_guid', 'pmc_u_id', 'pmc_from', 'pmc_to_openid', 'pmc_to_name', 'pmc_pay_by', 'pmc_money', 'pmc_des'];
			foreach($mustArr as $filed)
			{
				if(!isset($dataArr[$filed]))
				{
					return LibFc::ReturnData(false, $filed.'参数必填');
				}
			}

			if(preg_match('/[0-9a-zA-Z]{32}/', $dataArr['pmc_guid']))
			{
				$res = $this->get('pa_mchpay', ['pmc_id'], sprintf(" and pmc_guid='%s'", $dataArr['pmc_guid']), true);
				if(!empty($res['data'])) return LibFc::ReturnData(false, '提供的pmc_guid已被使用');
			}
			else
			{
				return LibFc::ReturnData(false, '提供的pre_guid不符合规则');
			}

			if($dataArr['pmc_pay_by'] == 'weixin' && $dataArr['pmc_money'] > 200) return LibFc::ReturnData(false, '微信单次提现金额不得高于200元，请分批提现');
			if(empty($dataArr['pmc_u_id'])) return LibFc::ReturnData(false, '提供的pmc_u_id参数值不存在');

			if(empty($dataArr['pmc_account'])) return LibFc::ReturnData(false, '提供的pmc_account参数值不存在');

			$dataArr['pmc_atime'] = time();
			$dataArr['pmc_partner_trade_no'] = time().rand(10,99).$dataArr['pmc_u_id'];
			$res = $this->add('pa_mchpay', $dataArr);
			$dataArr['pmc_id'] = $res['data'];
		}
		$accountTag = $dataArr['pmc_account'];
		$setArr = [];
		$dataArr['err_code'] = 'SUCCESS';
		$dataArr['err_msg'] = '';
		switch($dataArr['pmc_pay_by'])
		{
			case 'weixin':
				//旧版企业付款（API V2）
				$input = new WxMchPay($accountTag);
				$WxPayApi = new WxPayApi($accountTag);
				$input->SetData('partner_trade_no', $dataArr['pmc_partner_trade_no']);
				$input->SetData('openid', $dataArr['pmc_to_openid']);
				$input->SetData('check_name', 'FORCE_CHECK');
				$input->SetData('re_user_name', $dataArr['pmc_to_name']);
				$input->SetData('amount', $dataArr['pmc_money']*100);
				$input->SetData('desc', $dataArr['pmc_des']);
				$result = $WxPayApi->mchPay($input);
				$setArr['pmc_payjson'] = json_encode($result);
				if($result['return_code'] == 'SUCCESS')
				{
					if($result['result_code'] == 'SUCCESS')
					{
						$input = new WxMchPay($accountTag);
						$input->SetData('partner_trade_no', $dataArr['pmc_partner_trade_no']);
						$result = $WxPayApi->getMchPay($input);
						$setArr['pmc_payjson'] = json_encode($result);
						if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS')
						{
							if($result['status'] == 'SUCCESS')
							{
								$setArr['pmc_payment_no'] = $result['detail_id'];
								$setArr['pmc_status'] = 1;
								$setArr['pmc_pay_time'] = strtotime($result['transfer_time']);
							}
						}
					}
					else
					{
						$dataArr['err_code'] = $result['err_code'];
						$dataArr['err_msg'] = $result['err_code_des'];
					}
				}
				else
				{
					$dataArr['err_code'] = 'SYSTEM';
					$dataArr['err_msg'] = $result['return_msg'];
				}

				/*
				//新版商家转账（API V3），暂不使用，保留代码
				$result = $this->wxMchTransfer($accountTag, $dataArr);
				$setArr['pmc_payjson'] = json_encode($result, JSON_UNESCAPED_UNICODE);
				if(!empty($result['out_bill_no']))
				{
					//package_info仅在发起转账时返回，查单接口不会返回，必须保留供前端拉起确认收款页
					$packageInfo = isset($result['package_info'])? $result['package_info']: '';
					//保持原逻辑：发起转账成功后立即查单，以查单结果为准更新到账状态
					$result = $this->getWxMchTransfer($accountTag, $dataArr['pmc_partner_trade_no']);
					if(!empty($packageInfo) && !empty($result['state']) && !in_array($result['state'], ['SUCCESS', 'FAIL', 'CANCELLED']))
						$result['package_info'] = $packageInfo;
					$setArr['pmc_payjson'] = json_encode($result, JSON_UNESCAPED_UNICODE);
					if(!empty($result['state']) && $result['state'] == 'SUCCESS')
					{
						$setArr['pmc_payment_no'] = $result['transfer_bill_no'];
						$setArr['pmc_status'] = 1;
						$setArr['pmc_pay_time'] = strtotime($result['update_time']);
					}
					else if(!empty($result['state']) && in_array($result['state'], ['FAIL', 'CANCELLED']))
					{
						$setArr['pmc_status'] = -1;
						$setArr['pmc_error_json'] = json_encode([
							'err_code'=>$result['state'],
							'err_code_des'=>isset($result['fail_reason'])? $result['fail_reason']: $result['state']
						], JSON_UNESCAPED_UNICODE);
					}
				}
				else
				{
					$dataArr['err_code'] = isset($result['code'])? $result['code']: 'SYSTEM';
					$dataArr['err_msg'] = isset($result['message'])? $result['message']: '微信商家转账请求失败';
				}
				$this->set('pa_mchpay', $setArr, sprintf(" AND pmc_id=%d", $dataArr['pmc_id']));
				*/
			break;
			case 'alipay':
				$MainAliPay = new MainAliPay();
				$bizArr = [
					'out_biz_no'=>$dataArr['pmc_partner_trade_no'],
					'payee_type'=>'ALIPAY_LOGONID',
					'payee_account'=>$dataArr['pmc_to_openid'],
					'amount'=>$dataArr['pmc_money'],
					'payee_real_name'=>$dataArr['pmc_to_name'],
					'remark'=>$dataArr['pmc_des'],
				];
				$res = $MainAliPay->getApi('AlipayFundTransToaccountTransferRequest', $bizArr);
				$result = $res['data'];
				if(!empty($result['order_id']))
				{
					$bizArr = ['out_biz_no'=>$dataArr['pmc_partner_trade_no']];
					$res = $MainAliPay->getApi('AlipayFundTransOrderQueryRequest', $bizArr, [], false);
					$result = $res['data'];
					$setArr['pmc_payjson'] = json_encode($result);
					if($result['status'] == 'SUCCESS')
					{
						$setArr['pmc_status'] = 1;
						$setArr['pmc_payment_no'] = $result['order_id'];
						$setArr['pmc_pay_time'] = strtotime($result['pay_date']);
					}
				}
				else
				{
					$dataArr['err_code'] = $result['sub_code'];
					$dataArr['err_msg'] = $result['sub_msg'];
				}
				$this->set('pa_mchpay', $setArr, sprintf(" AND pmc_id=%d", $dataArr['pmc_id']));
			break;
		}
		$this->MainDb->End();
		//返回数据
		$res = $this->get('pa_mchpay', $filedArr, sprintf(" and pmc_id=%d", $dataArr['pmc_id']), true);
		$res['data']['err_code'] = $dataArr['err_code'];
		$res['data']['err_msg'] = $dataArr['err_msg'];
		return LibFc::ReturnData(true, $res['data']);
	}


	/**
	  * @method 查询企业转账
	  * @param  pmcId  int  转账记录ID
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['pre_id'=>xxxx, 'pre_por_id'=>'', 'pre_status'=>''....]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function getMchPay($pmcId)
	{
		$pmcId = (int) $pmcId;
		$res = $this->get('pa_mchpay', ['*'], sprintf(" AND pmc_id=%d", $pmcId), true);
		if(empty($res['data'])) return LibFc::ReturnData(false, 'getMchPay 转账订单不存在');
		$mchArr = $res['data'];
		if($mchArr['pmc_status'] == 0)
		{
			$accountTag = $mchArr['pmc_account'];
			switch($mchArr['pmc_pay_by'])
			{
				case 'weixin':
					//旧版企业付款查询（API V2）
					$input = new WxMchPay($accountTag);
					$WxPayApi = new WxPayApi($accountTag);
					$input->SetData('partner_trade_no', $mchArr['pmc_partner_trade_no']);
					$result =$WxPayApi->getMchPay($input);
					$setArr['pmc_payjson'] = json_encode($result, JSON_UNESCAPED_UNICODE);
					if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS')
					{
						if($result['status'] == 'SUCCESS')
						{
							$setArr['pmc_payment_no'] = $result['detail_id'];
							$setArr['pmc_status'] = 1;
							$setArr['pmc_pay_time'] = strtotime($result['transfer_time']);
						}
					}
					else
					{
						if($result['return_code'] == 'SUCCESS')
						{
							if($result['result_code'] == 'FAIL' && in_array($result['err_code'], ['NAME_MISMATCH', 'NOT_FOUND']))
							{
								$setArr['pmc_status'] = -1;
								$setArr['pmc_error_json'] = json_encode(['err_code'=>$result['err_code'], 'err_code_des'=>$result['err_code_des']], JSON_UNESCAPED_UNICODE);
							}
							$this->set('pa_mchpay', $setArr, sprintf(" AND pmc_id=%d", $mchArr['pmc_id']));
						}
						else
						{
							$this->set('pa_mchpay', $setArr, sprintf(" AND pmc_id=%d", $mchArr['pmc_id']));
							return LibFc::ReturnData(false, $result['return_msg']);
						}
					}

					/*
					//新版商家转账查单（API V3），暂不使用，保留代码
					$packageInfo = '';
					if(!empty($mchArr['pmc_payjson']))
					{
						$oldPayResult = json_decode($mchArr['pmc_payjson'], true);
						if(!empty($oldPayResult['package_info'])) $packageInfo = $oldPayResult['package_info'];
					}
					$result = $this->getWxMchTransfer($accountTag, $mchArr['pmc_partner_trade_no']);
					if(!empty($packageInfo) && !empty($result['state']) && !in_array($result['state'], ['SUCCESS', 'FAIL', 'CANCELLED']))
						$result['package_info'] = $packageInfo;
					$setArr['pmc_payjson'] = json_encode($result, JSON_UNESCAPED_UNICODE);
					if(!empty($result['state']))
					{
						if($result['state'] == 'SUCCESS')
						{
							$setArr['pmc_payment_no'] = $result['transfer_bill_no'];
							$setArr['pmc_status'] = 1;
							$setArr['pmc_pay_time'] = strtotime($result['update_time']);
						}
						else if(in_array($result['state'], ['FAIL', 'CANCELLED']))
						{
							$setArr['pmc_status'] = -1;
							$setArr['pmc_error_json'] = json_encode([
								'err_code'=>$result['state'],
								'err_code_des'=>isset($result['fail_reason'])? $result['fail_reason']: $result['state']
							], JSON_UNESCAPED_UNICODE);
						}
					}
					else
					{
						$errCode = isset($result['code'])? $result['code']: 'SYSTEM';
						$errMsg = isset($result['message'])? $result['message']: '微信商家转账查单失败';
						if($errCode == 'NOT_FOUND')
						{
							$setArr['pmc_status'] = -1;
							$setArr['pmc_error_json'] = json_encode(['err_code'=>$errCode, 'err_code_des'=>$errMsg], JSON_UNESCAPED_UNICODE);
						}
						$this->set('pa_mchpay', $setArr, sprintf(" AND pmc_id=%d", $mchArr['pmc_id']));
						if($errCode != 'NOT_FOUND') return LibFc::ReturnData(false, $errMsg, $errCode);
					}
					*/
				break;
				case 'alipay':
					$MainAliPay = new MainAliPay();
					$bizArr = ['out_biz_no'=>$mchArr['pmc_partner_trade_no']];
					$res = $MainAliPay->getApi('AlipayFundTransOrderQueryRequest', $bizArr);
					$result = $res['data'];
					$setArr['pmc_payjson'] = json_encode($result, JSON_UNESCAPED_UNICODE);
					if($result['status'] == 'SUCCESS')
					{
						$setArr['pmc_status'] = 1;
						$setArr['pmc_payment_no'] = $result['order_id'];
						$setArr['pmc_pay_time'] = strtotime($result['pay_date']);
					}
				break;
			}
			$this->set('pa_mchpay', $setArr, sprintf(" AND pmc_id=%d", $mchArr['pmc_id']));
			$mchArr = array_merge($mchArr, $setArr);
		}
		return LibFc::ReturnData(true, $mchArr);
	}



	/**
	  * @method 关闭微信平台的支付订单
	  * @param  $out_trade_no 微信平台out_trade_no
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>[]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	private function closeWxPay($account, $out_trade_no)
	{
		//关闭订单
		$WxPay = new WxPayUnifiedOrder($account);
		$WxPayApi = new WxPayApi($account);
		$WxPay->SetOut_trade_no($out_trade_no);
		$result = $WxPayApi->closeOrder($WxPay);
		if(array_key_exists("return_code", $result) && $result["return_code"] == "SUCCESS")
		{
			if(array_key_exists("result_code", $result) && $result["result_code"] == "SUCCESS")
			{
				return LibFc::ReturnData(true);
			}
			else
			{
				return LibFc::ReturnData(false, $result["err_code_des"], $result["err_code"]);
			}
		}
		return LibFc::ReturnData(false, $result["return_msg"], $result["return_code"]);
	}


	
	/**
	  * @method 获取微信支付订单的信息 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
	  * @param  $orderId 支付订单ID
	  * @param  $type transaction_id || out_trade_no
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['por_id'=>, 'por_status'=>, 'por_pay_time'=>]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function getWxPayOrder($account, $orderId, $type = 'transaction_id')
	{
		//query:{"appid":"wx0f4101f7c0262758","attach":[],"bank_type":"CITIC_CREDIT","cash_fee":"1","fee_type":"CNY","is_subscribe":"Y","mch_id":"1425099302","nonce_str":"IXvNCRk38gFdj2Fy","openid":"owl8Js8Cyr0AgLIkqeNIRhcBcF94","out_trade_no":"500028","result_code":"SUCCESS","return_code":"SUCCESS","return_msg":"OK","sign":"C63252151CE509BF8AF4697DB6B7B3CE","time_end":"20170817160314","total_fee":"1","trade_state":"SUCCESS","trade_type":"NATIVE","transaction_id":"4003352001201708176720013713"}
		$result = [];
		$WxPay = new WxPayOrderQuery($account);
		switch($type)
		{
			case 'out_trade_no': $WxPay->SetOut_trade_no($orderId);  break;
			case 'transaction_id': $WxPay->SetTransaction_id($orderId); break;
		}
		$WxPayApi = new WxPayApi($account);
		$result = $WxPayApi->orderQuery($WxPay);
		if(array_key_exists("return_code", $result) 
			&& $result["return_code"] == "SUCCESS" 
			&& array_key_exists("result_code", $result) 
			&& $result["result_code"] == "SUCCESS"
			&& array_key_exists("trade_state", $result) )
		{
			switch($result["trade_state"])
			{
				case 'SUCCESS':
					//成功支付 通过out_trade_no 修改订单状态
					$setArr = [
						'por_status' => 1,
						'por_transaction_id' => $result['transaction_id'],
						'por_pay_time' => strtotime($result['time_end']),
						'por_payjson' => json_encode($result),
						'por_check_by' => '系统',
						'por_check_time' => time(),
						'por_money' => sprintf('%.2f', $result['total_fee']/100),
						'por_return_etime' => 0
					];
					$this->set('pa_order', $setArr, sprintf(" AND por_trade_no='%s'", LibFc::Escape($result['out_trade_no'])));
					$result['por_status'] = 1;
				break;
				case 'CLOSED':
					$setArr = [
						'por_status' => -1,
						'por_payjson' => json_encode($result),
						'por_return_etime' => 0
					];
					$this->set('pa_order', $setArr, sprintf(" AND por_trade_no='%s'", LibFc::Escape($result['out_trade_no'])));
					$result['por_status'] = -1;
				break;
			}
		}
		return LibFc::ReturnData(true, $result);
	}


	/**
	  * @method 下载资金账单
	  * @author soul
	  * @copyright 2017/8/16
	  * @return
			成功：['status'=>true, 'data'=>['pmc_u_id', 'err_msg'=>''....]]
			失败：['status'=>false, 'data'=>'xxx', 'code'=>'xxx']
	  */
	public function downloadfundflow()
	{
		$accountTagArr = [
			'PJL'=>['weixin', 'alipay'],
			'YP'=>['weixin']
		];
	
		//查询最小日期
		$res = $this->get('pa_order', ["DISTINCT FROM_UNIXTIME(por_pay_time, '%Y-%m-%d') as pay_date"], ' and por_pay_time > 1577808000 and por_zhangdan = 0 and por_transaction_id is not null');
		$billDateArr = array_column($res['data'], 'pay_date');

		$res = $this->get('pa_refund', ["DISTINCT FROM_UNIXTIME(pre_refund_time, '%Y-%m-%d') as pay_date"], ' and pre_refund_time > 1577808000 and pre_zhangdan = 0 and pre_refund_id is not null');
		$billDateArr = array_merge($billDateArr, array_column($res['data'], 'pay_date'));
		$billDateArr = array_unique($billDateArr);
		sort($billDateArr);

		foreach($accountTagArr as $accountTag=>$typeArr)
		{
			foreach($billDateArr as $billDate)
			{
				if(strtotime($billDate) >= strtotime(date('Y-m-d'))) continue;
				$setOrderArr = [];
				foreach($typeArr as $type)
				{
					switch($type)
					{
						case 'weixin':
							$input = new WxPayDownloadBill($accountTag);
							$WxPayApi = new WxPayApi($accountTag);
							$input->SetBill_date(date('Ymd', strtotime($billDate)));
							$input->SetBill_type('ALL');
							$result = $WxPayApi->downloadBill($input);
							$result = explode("\r", $result);
							$filedArr = [];
							foreach($result as $kr=>$row)
							{
								$rowArr = explode(',', $row);
								$rowVal = [];
								if($kr == 0)
								{
									$filedArr = $rowArr;
								}
								else
								{
									foreach($rowArr as $kk=>$vv)
									{
										$rowVal[$filedArr[$kk]] = trim($vv, '`');
									}
									if(!empty($rowVal['商品名称']))
									{
										$setOrderArr[] = [
											'por_trade_no'=>$rowVal['商户订单号'],
											'service_fee'=>$rowVal['手续费'],
											'pre_out_refund_no'=>strlen($rowVal['商户退款单号']) > 5? $rowVal['商户退款单号']: ''
										];
									}
								}
							}
						break;
						case 'alipay':
							$MainAliPay = new MainAliPay();
							$bizArr = [
								'bill_date'=>$billDate,
								'bill_type'=>'trade'
							];
							$res = $MainAliPay->getApi('AlipayDataDataserviceBillDownloadurlQueryRequest', $bizArr, [], false);
							$result = $res['data'];
							$filedArr = [];

							if($result['sub_code'] == 'isp.bill_not_exist') break;
							if(empty($result['bill_download_url'])) return LibFc::ReturnData(false, $billDate.'下载支付宝对账单失败');
							
							$fileName = 'alizd_'.$billDate;
							$todir = mvc::$cfg['AUTOLOAD']['Main']['path'].'cache/'.$fileName;
							$tmpZip = $todir.'.zip';
							$LibHttp = new LibHttp();
							$zipData = $LibHttp->fetch($result['bill_download_url']);
							file_put_contents($tmpZip, $zipData);
							$zip = new ZipArchive();
							if($zip->open($tmpZip) !==TRUE) return LibFc::ReturnData(false, $billDate.'支付宝对账单解压失败');
							$zip->extractTo($todir);
							$zip->close();
							if($handle = opendir($todir))
							{
								while(($file = readdir($handle))!==false)
								{
									if(stripos($file, 'csv') === false) continue;
									$csvFile = $todir.'/'.$file;

									$handle2 = fopen($csvFile, 'r');
									while (($data = fgetcsv($handle2)) !== false)
									{
										if(count($data) < 25) continue;
										foreach($data as $kk=>$vv)
										{	
											$data[$kk] = iconv('gbk', 'utf-8', $vv);
										}
										if(empty($filedArr))
										{
											$filedArr =  $data;
										}
										else
										{
											$rowVal = [];
											foreach($data as $kk=>$vv)
											{
												$rowVal[$filedArr[$kk]] = $vv;
											}
											
											if(!empty($rowVal['商户订单号']))
											{
												$setOrderArr[] = [
													'por_trade_no'=>trim($rowVal['商户订单号']),
													'service_fee'=>-$rowVal['服务费（元）'],
													'pre_out_refund_no'=>strlen($rowVal['退款批次号/请求号']) > 5 ? $rowVal['退款批次号/请求号'] : ''
												];
											}
										}
									}
									fclose($handle2);
								}
								closedir($handle);
							}
							@unlink($tmpZip);
							LibDir::DeleteDir($todir);
						break;
					}
				}
				$this->MainDb->Begin();
				foreach($setOrderArr as $v)
				{
					$v['service_fee'] = sprintf("%.2f", $v['service_fee']);
					if(!empty($v['pre_out_refund_no']))
					{
						$this->set('pa_refund', ['pre_service_fee'=>$v['service_fee'], 'pre_zhangdan'=>1], sprintf(" and pre_out_refund_no = '%s'", $v['pre_out_refund_no']));
					}
					else if(!empty($v['por_trade_no']))
					{
						$this->set('pa_order', ['por_service_fee'=>$v['service_fee'], 'por_zhangdan'=>1], sprintf(" and por_trade_no = '%s'", $v['por_trade_no']));
					}
				}
				
				//支付宝退款不退手续费
				$this->set('pa_refund', ['pre_service_fee'=>0.00, 'pre_zhangdan'=>1], " and pre_status = 1 and pre_zhangdan = 0 and pre_por_id in (select por_id from pa_order where por_pay_method = 'alipay')");

				$this->MainDb->End();
			}
		}
		return LibFc::ReturnData(true);
	}


	/**
	  * @method 微信商家转账（API V3）
	  * @param  $accountTag  string  支付账号标识
	  * @param  $dataArr     array   转账订单
	  * @return array
	  */
	private function wxMchTransfer($accountTag, $dataArr)
	{
		$WxPayV3Api = new WxPayV3Api($accountTag);
		$styleNameArr = [
			'PJLSHARE'=>'邀请赚钱提现',
			'PJLYETX'=>'跑街令余额提现'
		];
		if(empty($dataArr['pmc_style']) || empty($styleNameArr[$dataArr['pmc_style']]))
			throw new WxPayException('微信商家转账pmc_style不支持');
		$styleName = $styleNameArr[$dataArr['pmc_style']];

		$userName = '';
		if(!empty($dataArr['pmc_to_name']))
			$userName = $WxPayV3Api->encryptSensitive($dataArr['pmc_to_name']);

		$body = [
			'appid'=>$WxPayV3Api->getAppid(),
			'out_bill_no'=>$dataArr['pmc_partner_trade_no'],
			'transfer_scene_id'=>'1009',
			'openid'=>$dataArr['pmc_to_openid'],
			'transfer_amount'=>(int) round($dataArr['pmc_money'] * 100),
			'transfer_remark'=>$dataArr['pmc_des'],
			'transfer_scene_report_infos'=>[
				[
					'info_type'=>'采购商品名称',
					'info_content'=>$styleName
				]
			]
		];
		if(!empty($userName)) $body['user_name'] = $userName;

		return $WxPayV3Api->post('/v3/fund-app/mch-transfer/transfer-bills', $body);
	}


	/**
	  * @method 按商户单号查询微信商家转账（API V3）
	  * @param  $accountTag  string  支付账号标识
	  * @param  $outBillNo   string  商户单号
	  * @return array
	  */
	private function getWxMchTransfer($accountTag, $outBillNo)
	{
		$WxPayV3Api = new WxPayV3Api($accountTag);
		$path = '/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/'.rawurlencode($outBillNo);
		return $WxPayV3Api->get($path);
	}
}
