<?php

/**
 * Created by PhpStorm.
 * User: stanley-king
 * Date: 15/12/9
 * Time: 上午12:25
 */

define(WXPAY_PATH, BASE_DATA_PATH . '/api/open_wxpay');
require_once(WXPAY_PATH . '/lib/OpenWxPay.Api.php');
require_once(WXPAY_PATH . '/lib/OpenWxPay.Config.php');
require_once(WXPAY_PATH . '/lib/OpenWxPay.Data.php');
require_once(WXPAY_PATH . '/lib/OpenWxPay.Exception.php');
require_once(WXPAY_PATH . '/lib/OpenWxPay.Notify.php');
require_once(BASE_ROOT_PATH . '/helper/predeposit_helper.php');


class app_payControl extends mbMemberControl
{
    private static $pay_types = array('wxpay', 'alipay');
    const wx_notifyurl  = BASE_SITE_URL . '/mobile/wxnotify.php';
    const ali_notifyurl = BASE_SITE_URL . '/mobile/alipay_notify_url.php';

    const wx_orderquery = 'https://api.mch.weixin.qq.com/pay/orderquery';
    const alipay_rsa_private = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL+I5/3VVhfpc3TmsUjuwc8mrZycavjuE4MV9Z+EXDvPy55PAYjDvKfMtRMCsJYgO4R0fyyb1OhvglyXUKLFajxOhUm/4K2hnI1E/+8zPbY0CU5Osr4C9sxWHtY66ugTx+O4W3e4CxYTfHn+C6EuiYJ2DWJig+Obphd8CPFYFzLxAgMBAAECgYA+og9zEytXIHEv/ixlNCZOjlBhkUjt5DSfPjQXGNpseLQWLbHLvm5X1Po1oECMpzevRcU8mizSYXyYuKaWw8XMJ7/CC6A8fSBdlUeLEfTfisurEnzeUsal2K/n+WAAFj+TUncnqYtEqCCT+9c4jVkfik7FNxjbcio9p27QKDzYwQJBAOlWs593knByuSFOVnIiphhKlZy+6MUxquxhP+3NlXVaTCHHbBl8xt3fLqLmrXPUHvAt39wJ8fAvLDuNUQgP2gkCQQDSIt7bZi2hmzqfXK9rqVyJ16o0Hwqa8Z6PYhodSSsf61h3+wxdEpDFxIV9JnPWBPhCxcX+d1VddyLZacXbKuupAkBpwFesID8II5Zv19cp5zYrsDHaVlOce4QhmXmlxxTDmOcEMCN38asXhzzVq4JVCn/zDnd0fDVgS6DaZJOi+bwxAkAJg2iheCvCsDtkMZcDgcRdvTTIbUtWnm+2QBO8la5tIIN90xDJOejx+yar9syxuMHgjAGdtptXwugB/cbmWDgZAkEAiRoMv6p7WKNU34kZqpvXMIhN6hUihquVFZDJ7wiBr1tCLw/kW3uhciCViM68FgLStuefTfssgr9+oHVw/o4GjA==";

    public function calc_predOp()
    {
        $pay_sn = $_GET['paysn'];
        $validate = new Validator();
        $validate->setValidate(Validator::verify_serialnum($pay_sn));
        $validate->setValidate(Validator::verify_number($pay_sn));
        $error = $validate->validate();
        if ($error != '') {
            return self::outerr(errcode::ErrParamter, $error);
        }

        $logic_payment = Logic('payment');
        $member_info = array('member_id' => $_SESSION['member_id'], 'member_name'  => $_SESSION['member_name']);
        $canuse_pred = $logic_payment->calcPredeposit($pay_sn,$member_info,$avail_pred,$used_pred);

        if($used_pred === false) {
            return self::outerr(errcode::ErrOrder,"取不到订单信息.");
        } else {
            return self::outsuccess(array("available_predeposit" => $avail_pred,"canuse_predeposit" => $canuse_pred,'used_predposit' => $used_pred));
        }
    }

    /*
     * 微信获取支付数据
     */
    public function uniorderOp()
    {
        $pay_sn = $_GET['paysn'];
        $payment = $_GET['payment'];
        $vcode = $_GET['vcode'];

        if(empty($vcode)) {
            return self::outerr(errcode::ErrPayment, "抱歉，请升级到最新版本.");
        }

        if (in_array($payment, self::$pay_types) == false) {
            return self::outerr(errcode::ErrPayment, "err paytype {$payment}: only for wxpay,alipay");
        }

        $logic_payment = Logic('payment');
        // 尝试使用红包
        $usebonus = intval($_GET['usebonus']);
        $member_info = array('member_id' => $_SESSION['member_id'], 'member_name'  => $_SESSION['member_name']);
        if (intval($usebonus) === 1) {
            $logic_payment->payPredepositEx($pay_sn,$member_info);
        }

        //重新计算所需支付金额
        $result = $logic_payment->getRealOrderInfo($pay_sn, $_SESSION['member_id']);
        if (intval($result['data']['api_pay_state']) != 0) {
            return self::outerr(errcode::ErrPayment, $result['msg']);
        }

        // 判断是否需要支付
        $output = array();
        $pay_money = intval(doubleval($result['data']['api_pay_amount']) * 100 + 0.5);
        if ($pay_money >= 1)
        {
            $output['need_pay'] = 1;
            $ret = $this->api_pay($result['data'], $payment);
            if ($ret != false) {
                $output['pay_info'] = $ret;
            } else {
                return self::outerr(errcode::ErrPayment, '支付失败.');
            }
        }
        else
        {
            $output['need_pay'] = 0;
            $result = self::update_order($pay_sn, $pay_sn, 'bonus');  // 更新订单
            // 推送到oms
            if (isset($result) && $result['state'])
            {
                if(is_pushoms())
                {
                    $logic_delivery = Logic('delivery');
                    $ret = $logic_delivery->putOrder($pay_sn, $pay_sn);
                    if(empty($ret)) { //todo must add to 定时任务
                        Log::record("Put order to oms error: pay_sn={$pay_sn},bonus pay.",Log::ERR);
                    }
                }
            }
        }

        self::outsuccess($output);
    }

    /**
     * 支付订单查询
     *
     * 输入参数：
     * key: token
     * paysn: 支付sn
     * payment: 支付类型
     * transaction_id:
     */
    public function orderqueryOp()
    {
        $pay_sn = $_GET['paysn'];
        $payment = $_GET['payment'];
        $tractid = $_GET['transaction_id'];

        if ($payment == 'wxpay') {
            $input = new OpenWxPayOrderQuery();
            $input->SetOut_trade_no($pay_sn);
            $input->SetTransaction_id($tractid);
            $result = OpenWxPayApi::orderQuery($input);

            if (array_key_exists("return_code", $result)
                && array_key_exists("result_code", $result)
                && $result["return_code"] == "SUCCESS"
                && $result["result_code"] == "SUCCESS"
            ) {
                return self::outsuccess($result);
            }
            return self::outerr(errcode::ErrPayment, '支付失败.');
        } else {
            return self::outerr(errcode::ErrPayment, "错误的参数:payment = {$payment}");
        }
    }

    /**
     * 支付返回
     *
     * @param $pay_info
     * @param $payment
     * @return array
     */
    private function api_pay($pay_info, $payment)
    {
        $subject = $pay_info['subject'];
        $pay_sn = $pay_info['pay_sn'];
        $fee = intval(doubleval($pay_info['api_pay_amount']) * 100 + 0.5);
        $order_sn = $pay_info['order_list'][0]['order_sn'];

        if ($payment == 'wxpay') {
            return $this->uniorder($subject, $pay_sn, $fee,$order_sn);
        } else if ($payment === 'alipay') {
            $ret = array();
            $ret['rsa_private'] = self::alipay_rsa_private;                 // 私钥
            $ret['partner'] = '2088121219613123';                           // 合作者身份ID
            $ret['seller_id'] = 'napheir.ao@lrlz.com';                      // 签约卖家支付宝账号
            $ret['out_trade_no'] = $pay_sn;   // 商户网站唯一订单号
            $ret['subject'] = $subject;                                     // 商品名称
            $ret['body'] = "order_sn={$order_sn}";                          // 商品详情
            $total_fee = intval(doubleval($pay_info['api_pay_amount']) * 100 + 0.5) / 100;
            $ret['total_fee'] =  $total_fee;// 商品金额
            $ret['notify_url'] = self::ali_notifyurl;                       // 服务器异步通知页面路径
            $ret['service'] = 'mobile.securitypay.pay';                     // 服务器接口名称，固定值
            $ret['payment_type'] = '1';                                     // 支付类型，固定值
            $ret['_input_charset'] = 'utf-8';                               // 参数编码，固定值
            $ret['it_b_pay'] = '30m';                                       // 设置未付款交易的超时时间 30min
            $ret['return_url'] = 'http://';                                 // 支付宝完成请求后，当前页面跳转到商户指定页面的路径，可空
            return array('payment' => $payment, 'content' => $ret);
        }
    }

    /**
     * 格式化参数格式化成url参数
     */
    private function to_url_params($values)
    {
        $buff = "";
        foreach ($values as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    private function make_sign($values)
    {
        //签名步骤一：按字典序排序参数
        ksort($values);
        $string = $this->to_url_params($values);
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . OpenWxPayConfig::KEY;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /**
     * 更新订单状态
     *
     * @param $out_trade_no
     * @param $trade_no
     * @param $payment
     * @param $transaction_id
     * @return array
     */
    public static function update_order($out_trade_no, $trade_no, $payment)
    {
        $logic_payment = Logic('payment');

        $tmp = explode('|', $out_trade_no);
        $out_trade_no = $tmp[0];
        if (!empty($tmp[1])) {
            $order_type = $tmp[1];
        } else {
            $order_pay_info = Model('order')->getOrderPayInfo(array('pay_sn' => $out_trade_no));
            if (empty($order_pay_info)) {
                $order_type = 'v';
            } else {
                $order_type = 'r';
            }
        }

        if ($order_type == 'r') {
            $result = $logic_payment->getRealOrderInfo($out_trade_no);
            if (intval($result['data']['api_pay_state'])) {
                return array('state' => true);
            }
            $order_list = $result['data']['order_list'];
            $result = $logic_payment->updateRealOrder($out_trade_no, $payment, $order_list, $trade_no);
        } elseif ($order_type == 'v') {
            $result = $logic_payment->getVrOrderInfo($out_trade_no, null, true);
            if ($result['data']['order_state'] != ORDER_STATE_NEW) {
                return array('state' => true);
            }
            $result = $logic_payment->updateVrOrder($out_trade_no, $payment, $result['data'], $trade_no);
        }

        return $result;
    }

    private function toString($order)
    {
        $ret = '';
        foreach ($order as $key => $val) {
            $ret .= $key . "=" . $val;
            $ret .= '&';
        }

        return $ret;
    }

    public static function check_fee($pay_sn,$total_fee,&$need_pay)
    {
        $logic_payment = Logic('payment');
        $result = $logic_payment->getRealOrderInfo($pay_sn);

        if (intval($result['data']['api_pay_state']) != 0) {
            return false;
        }

        $need_pay = intval($result['data']['api_pay_amount'] * 100 + 0.5);
        $total_fee = intval($total_fee * 100 + 0.5);

        return ($need_pay === $total_fee);
    }

    /**
     * @return array
     * @throws OpenWxPayException
     */
    private function uniorder($body, $pay_sn, $fee,$order_sn)
    {
        Log::record("body={$body},paysn={$pay_sn},fee={$fee}", Log::DEBUG);
        $input = new OpenWxPayUnifiedOrder();
        $input->SetBody($body); //商品或支付单简要描述
        $input->SetAttach($pay_sn); //附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据
        $out_trade_no = $pay_sn . sprintf("%03d",mt_rand(0,999)); //给微信用的每次重新生成的商户订单SN, 避免二次支付, 数额修改导致支付失败
        $input->SetOut_trade_no($out_trade_no);//商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号

        $input->SetTotal_fee("{$fee}");//订单总金额，单位为分，详见支付金额
        $input->SetTime_start(date("YmdHis")); //订单生成时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
        $input->SetTime_expire(date("YmdHis", time() + 600));//订单失效时间，格式为yyyyMMddHHmmss，如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
        $input->SetNotify_url(self::wx_notifyurl);
        $input->SetTrade_type("APP");//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付，统一下单接口trade_type的传参可参考这里,MICROPAY--刷卡支付，刷卡支付有单独的支付接口，不调用统一下单接口
        $order = OpenWxPayApi::unifiedOrder($input);

        $sorder = $this->toString($order);
        Log::record($sorder, Log::DEBUG);

        if (array_key_exists('err_code', $order)) {
            return false;
        }

        $ret = array(); {
            $ret['appid'] = $order["appid"];
            $ret['noncestr'] = OpenWxPayApi::getNonceStr();
            $ret['package'] = 'Sign=WXPay';
            $ret['partnerid'] = OpenWxPayConfig::MCHID;
            $ret['prepayid'] = $order['prepay_id'];
            $timeStamp = time();
            $ret['timestamp'] = "{$timeStamp}";
            $ret['sign'] = $this->make_sign($ret);
        }

        return $ret;
    }
}