<?php
// +----------------------------------------------------------------------
// | likeshop100%开源免费商用商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码，建议反馈是我们前进的动力
// | 开源版本可自由商用，可去除界面版权logo
// | 商业版本务必购买商业授权，以免引起法律纠纷
// | 禁止对系统程序代码以任何目的，任何形式的再发布
// | gitee下载：https://gitee.com/likeshop_gitee
// | github下载：https://github.com/likeshop-github
// | 访问官网：https://www.likeshop.cn
// | 访问社区：https://home.likeshop.cn
// | 访问手册：http://doc.likeshop.cn
// | 微信公众号：likeshop技术社区
// | likeshop团队 版权所有 拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshopTeam
// +----------------------------------------------------------------------

namespace app\common\logic;

use app\common\server\AliPayServer;
use app\common\server\WeChatPayServer;
use app\common\model\{Client_, Order, Pay, User};
use think\facade\Env;

class PaymentLogic extends LogicBase
{

    protected static $error = '';
    protected static $return_code = 0;

    /**
     * Notes: 错误信息
     * @return string
     * @author 段誉(2021/2/1 11:19)
     */
    public static function getError()
    {
        return self::$error;
    }

    /**
     * Notes: 返回状态码
     * @return int
     * @author 段誉(2021/2/1 11:19)
     */
    public static function getReturnCode()
    {
        return self::$return_code;
    }


    /**
     * Notes: 支付
     * @param $from
     * @param $order
     * @param $order_source
     * @return array|bool|string
     * @author 段誉(2021/2/1 11:19)
     */
    public static function pay($from, $order, $order_source)
    {
        switch ($order['pay_way']) {
            case Pay::WECHAT_PAY:

                $res = WeChatPayServer::unifiedOrder($from, $order, $order_source);
                if (false === $res) {
                    self::$error = WeChatPayServer::getError();
                }
                break;

            case Pay::ALI_PAY:

                $aliPay = new AliPayServer();
                $res = $aliPay->pay($from, $order, $order_source);
                if(false === $res) {
                    self::$error = $aliPay->getError();
                } else {
                    self::$return_code = 20001;//特殊状态码,用于前端判断
                }
                break;
            case 8:
                $ttPay = new ttPay();
                $res = $ttPay->run('order',$order);
              
                // $res = self::ttpay($order); 
                if(!empty($res['data'])) {
                    self::$return_code = 8888;//特殊状态码,用于前端判断 
                    $res = $res['data'];
                }else{
                     self::$error = $res['err_tips'];
                      $res = false;
                }
                
                break;

            default:
                self::$error = '订单异常';
                $res = false;
        }
        return $res;
    }
    
    //抖音支付 
     public static function ttpay($data)
    {
        $url = 'https://developer.toutiao.com/api/apps/ecpay/v1/create_order';
        $params['app_id'] = 'tt0523739e9a12236501';
        $params['out_order_no'] = (string)$data['order_sn'];
        $params['total_amount'] = (int)$data['order_amount'] * 100;
        $params['subject'] = 'subject';
        $params['body'] = 'body';
        $params['valid_time'] = 3600;
        
     
        $params['sign'] = self::ttsign($params,'ejAuHvbI472euyhb34aVyLD92ll9tgZCqWnMi0tX');
     
        
        $http = self::httpPost($url, $params);
        return json_decode($http,true);
    }
    
    //curl 
    public static function httpPost($url, $data = null)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        if (!$data) return false;
        if (is_array($data)) {
            $data = json_encode($data);
        }
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json; charset=utf-8',
            'Content-Length:' . strlen($data),
            'Cache-Control: no-cache',
            'Pragma: no-cache'
        ));
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $res = curl_exec($curl);
        curl_close($curl);
        return $res;
    }
    // 签名
    public static function ttsign($map,$secret)
    {  

         $rList = [];
        foreach($map as $k =>$v) {
            if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id")
                continue;
    
            $value = trim(strval($v)); 
    
            $len = strlen($value);
            if ($len > 1 && substr($value, 0,1)=="\"" && substr($value, $len-1)=="\"")
                $value = substr($value,1, $len-1);
            $value = trim($value);
            if ($value == "" || $value == "null")
                continue;
            $rList[] = $value;
        }
        $rList[] = $secret;
        sort($rList, SORT_STRING);
    
        
        return md5(implode('&', $rList));
    }








    /**
     * Notes: 是否在白名单内支付
     * @param $user_id
     * @author 段誉(2021/2/24 10:01)
     * @return bool
     */
    public static function isPayWhiteList($user_id)
    {
        $white_list = Env::get('wechat.white_list', '');
        $white_list = explode(',', $white_list);
        if (in_array($user_id, $white_list)) {
            return true;
        }
        return false;
    }
}

Class ttPay{
   
    private $api_url='https://developer.toutiao.com/api/apps/ecpay/v1/';
    private $app_id;
    private $token;
    private $salt;

    public function __construct() {
        $this->app_id = 'tt0523739e9a12236501';
        $this->token='123qazqweeesdflomswwe';
        $this->salt='ejAuHvbI472euyhb34aVyLD92ll9tgZCqWnMi0tX';
        //  $this->salt='58280e4f36d88e93d7a4be9f0e590b2302a462c5';
    }        
        
    public function run($action,$order){ 
         $action=$action?$action:'order';
         if(!in_array($action,['order','query','refund','settle','notify','set'])){
            echo '非法请求';die;
        }
        return $this->$action($order); 
    }
    
    //下单
    private function  order($order){
        $data=[
            'out_order_no'=>$order['order_sn'],
            'total_amount'=>(int)$order['order_amount'] * 100,
            'subject'=>'购买服务',
            'body'=>'购买商品',
            'valid_time'=>3600,
        ];
        return $this->post('create_order',$data);
       
    }
    
    //查询订单
    private function  query(){
        $data=[
            'out_order_no'=>'2021110117254573565'
        ];
        $res=$this->post('query_order',$data,false);
        echo json_encode($res);die;
    }
    
    //订单退款
    private function refund(){
        $data=[
            'out_order_no'=>'2021110118351347832',
            'out_refund_no'=>$this->order_number(),
            'reason'=>'退款原因',
            'refund_amount'=>1,
        ];
        $res=$this->post('create_refund',$data);
        echo json_encode($res);die;
    }
    
    //订单分账
    private function settle(){
        $data=[
            'out_order_no'=>'2021110118301265990',
            'out_settle_no'=>$this->order_number(),
            'settle_desc'=>'分账描述',
            'settle_params'=>json_encode([]),//分润方参数 如[['merchant_uid'=>'商户号','amount'=>'10']]  可以有多个分账商户
        ];
        $res=$this->post('settle',$data);
        echo json_encode($res);die;
    }
    
    //支付设置回调测试
    private function set(){
        $content=file_get_contents('php://input');
        $this->log('log.txt',$content);
    }
    
    //回调
    private function notify(){
        $content=file_get_contents('php://input');
        if(empty($content)) return false;
        $this->log('notify.txt',$content);
        $content=json_decode($content,true);
        $sign=$this->handler($content);
        if($sign==$content['msg_signature']){
            $msg=json_decode($content['msg'],true); 
            echo '回调----'.$content['type']."\n";
            //这里更新应用业务逻辑代码，使用$msg跟应用订单比对更新订单,可以用 $content['type']判断是支付回调还是退款回调，payment支付回调 refund退款回调。
            $res=['err_no'=>0,'err_tips'=>'success'];
            echo json_encode($res);
        }
    }
    
    
    /**
    * 测试订单号，实际应用根据自己应用实际生成
    * @return string
    */
    private function order_number(){
        return date('YmdHis').rand(10000,99999);
    }
    
     /**
     * 请求小程序平台服务端
     * @param string $url 接口地址
     * @param array $data 参数内容
     * @param boolean $notify 是否有回调
     * @return array
    */
    private function post($method,$data,$notify=true){
        $data['app_id']=$this->app_id;
      
        $data['sign']=$this->sign($data);
        $url=$this->api_url.$method;
        $res=$this->http('POST',$url,json_encode($data),['Content-Type: application/json'],true);
        return json_decode($res,true);
    }
    

    /**
     * 回调验签
     * @param array $map 验签参数
     * @return stirng
    */
    private function handler($map){
        $rList = array();
        array_push($rList, $this->token);
        foreach($map as $k =>$v) {
            if ( $k == "type" || $k=='msg_signature')
                continue;
            $value = trim(strval($v));
            if ($value == "" || $value == "null")
                continue;
            array_push($rList, $value);
        }
        sort($rList,2);
        return sha1(implode($rList));
    }
    
    /**
     * 请求签名
     * @param array $map 请求参数
     * @return stirng
    */
    private function sign($map) {
        $rList = array();
        foreach($map as $k =>$v) {
            if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id")
                continue;
            $value = trim(strval($v));
            $len = strlen($value);
            if ($len > 1 && substr($value, 0,1)=="\"" && substr($value,$len, $len-1)=="\"")
                $value = substr($value,1, $len-1);
            $value = trim($value);
            if ($value == "" || $value == "null")
                continue;
            array_push($rList, $value);
        }
        array_push($rList, $this->salt);
        sort($rList, 2);
        return md5(implode('&', $rList));
    }

     /**
     * 写日志
     * @param string $path 日志路径
     * @param string $content 内容
    */
    private function log($path, $content){
        $file=fopen($path,  "a");
        fwrite($file, date('Y-m-d H:i:s').'-----'.$content."\n");
        fclose($file);
    }
    
    
    
    
    /**
     * 网络请求
     * @param stirng $method 请求模式
     * @param stirng  $url请求网关
     * @param array $params 请求参数
     * @param stirng  $header 自定义头
     * @param boolean  $multi 文件上传
     * @return array
     */
    private function http( $method = 'GET', $url,$params,$header = array(), $multi = false){
    	
        $opts = array(
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER     => $header
        );
        /* 根据请求类型设置特定参数 */
        switch(strtoupper($method)){
            case 'GET':
                $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
                break;
            case 'POST':
                //判断是否传输文件
                $params = $multi ? $params : http_build_query($params);
                $opts[CURLOPT_URL] = $url;
                $opts[CURLOPT_POST] = 1;
                $opts[CURLOPT_POSTFIELDS] = $params;
                break;
            default:
                throw new Exception('不支持的请求方式！');
        }
    	
        /* 初始化并执行curl请求 */
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $data  = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);
        if($error) throw new Exception('请求发生错误：' . $error);
        return  $data;
    }
    
    
}

