<?php

namespace loyalsoft\pay;

/**
 * Description of OrderNotice
 *  通用支付订单通知模型
 * @version
 *          1.0.0 Created at 2017-12-26. by --gwang
 * @author gwang (mail@wanggangzero.cn)
 * @copyright ? 2017-12-26, SJZ LoyalSoft Corporation & gwang. All rights reserved.
 */
class OrderNotice extends \loyalsoft\Object_ext {

    const orderTab = 'tpl_order_tab';

    /**
     * uid,zoneid,cpOrderId
     * @var string 充值回调透传参数(len=250)
     */
    public $callbackInfo;

    /**
     * @var int 充值金额 单位:分
     */
    public $amount;

    /**
     * @var string 订单ID (len=30)
     */
    public $cpOrderId;

    /**
     * @var string 平台UID
     */
    public $uid;

    /**
     * @var string 平台字符串
     */
    public $channel;

    /**
     *
     * @var type 订单状态: 0:创建订单,1:支付成功,2: 支付失败
     */
    public $status;

    /**
     *
     * @var type
     */
    protected $sdk_orderid;

    /**
     *
     * @var type
     */
    protected $otherInfo;

    /**
     * @return boolean 校验订单数据
     */
    public function Check() {
//        var_dump($this);
        $dbOrder = \loyalsoft\daoInst()->select()->from(self::orderTab)
                        ->where('cpOrderId')->eq($this->cpOrderId)
                        ->limit(1)->fetch();
//        var_dump($dbOrder);
        \loyalsoft\CLog::pay('查询订单结果: ' . var_export($dbOrder, TRUE));
        if (!$dbOrder) {
            \loyalsoft\CLog::pay('订单不存在! ' . $this);
            return false;
        }
        if ($dbOrder->status == 1) {
            \loyalsoft\CLog::pay('订单已经完成!' . $this);
            return false;
        }
        // 提取纯UID作比较
        $pureUID = function($str) {
//            var_dump($str);
            if (!strpos($str, "-")) {
                return $str;
            }
            return substr($str, strpos($str, "-") + 1);
        };
//        var_dump($this->uid);
        if ($pureUID($dbOrder->uid) != $pureUID($this->uid)) {
            \loyalsoft\CLog::pay('UID校验不匹配! ' . $pureUID($this->uid) . " (" . $pureUID($dbOrder->uid) . ")");
            return false;
        }
        if ($dbOrder->amount != $this->amount) {
            \loyalsoft\CLog::pay('金额校验不匹配! ' . $this . " (" . $dbOrder->amount . ")");
            return false;
        }
        return true;
    }

    /**
     * 检查重复的渠道订单id（目前仅在ios平台做了校验，其他都是后台通知。
     * @return boolean true 验证通过，false 验证失败，已经存在相同的订单id
     */
    public function CheckDuplicateSdkOrder() {
        $n = \loyalsoft\daoInst()->select()->from(self::orderTab)
                ->where('sdk_orderid')->eq($this->sdk_orderid)
                ->count();
        return $n <= 0;
    }

    /**
     * @return boolean 更新订单状态
     */
    public function UpdateOrderStatus() {
        $n = \loyalsoft\daoInst()->update(self::orderTab)
                ->data(array('status' => $this->status,
                    'sdk_orderid' => $this->sdk_orderid,
                    'otherInfo' => $this->otherInfo,
                    'close_ts' => \loyalsoft\now()))
                ->where('cpOrderId')->eq($this->cpOrderId)
                ->exec();
        return $n > 0;
    }

    /**
     * 识别UC后台通知数据
     * @param array $args
     * @return \loyalsoft\pay\OrderNotice
     */
    public static function Parse_UcOrder($args) {
        $o = new OrderNotice();
        $o->channel = "uc";                                                     # 渠道代码
        $o->cpOrderId = $args["data"]["cpOrderId"];                             # (后台)订单编号
        $o->status = ($args["data"]["orderStatus"] == "S") ? 1 : 2;             # 订单状态(九游返回值: S/F)
        $o->uid = $args['data']['accountId'];                                   # 玩家uid
        $o->amount = $args['data']['amount'] * 100;                             # 支付金额, uc 返回的单位是元
        $o->callbackInfo = $args['data']['callbackInfo'];                       # uid-uc,zoneid,cpOrderId
        $o->sdk_orderid = $args['orderId'];                                     # UC订单ID
        $o->otherInfo = $args['failedDesc'];                                    # 其他信息
        return $o;
    }

    /**
     * 解析易接后台通知数据
     * @param array $args
     */
    public static function Parse_1SDKOrder($args) {
        $o = new OrderNotice();
        $o->channel = "1sdk";                                                   # 渠道代码
        $ext = explode(',', $args['cbi']);
        $o->cpOrderId = $ext[2];                                                # 这个字段藏在透传参数中
        $o->status = ($args["st"] == "1") ? 1 : 2;                              # 订单状态(易接SDK返回值: 1/成功,其他失败)
        $o->uid = $args['uid'];                                                 # 玩家uid
        $o->amount = $args['fee'];                                              # 支付金额, 易接返回值单位是分
        $o->callbackInfo = $args['cbi'];                                        # 透传参数, uid-uc,zoneid,cpOrderId
        $o->sdk_orderid = $args['ssid'];                                        # 渠道订单id
        $o->otherInfo = $args['tcd'];                                           # 易接订单id
        return $o;
    }

    /**
     * 生成苹果支付订单数据.
     * @param array $argsClient
     * @param array $receipt 苹果凭证
     */
    public static function reParse_IOSOrder($argsClient, $receipt) {
        $o = new OrderNotice();
        $o->channel = "ios";                                                    # 渠道代码
        $o->uid = $argsClient->uid;                                             # 玩家uid
        $o->cpOrderId = $argsClient->cpOrderId;                                 # 这个字段藏在透传参数中
        $o->callbackInfo = $argsClient->callbackInfo;                           # 透传参数, uid-uc,zoneid,cpOrderId
        $o->status = ($receipt["status"] == "0") ? 1 : 2;                       # 订单状态(苹果返回值: 0/成功,其他失败)
        $product_id = $receipt['product_id'];                                   # 道具ID
        $itemModel = \loyalsoft\GameConfig::shop_getItem($product_id);          # 道具常量
        $o->amount = $itemModel->price * 100;                                   # 入库单位是分, 后台单位是元
        $o->sdk_orderid = $receipt['transaction_id'];                           # 交易订单id
        $o->otherInfo = $receipt['purchase_date'];                              # 购买时间
        return $o;
    }

    /**
     * 解析支付宝通知
     * @param type $args
     * @return  \loyalsoft\pay\OrderNotice
     */
    public static function Parse_alipayOrder($args) {
        $o = new OrderNotice();
        $exts = explode(',', urldecode($args['passback_params']));              # 透传参数

        $o->channel = "soft";                                                   # 渠道代码zfb?
        $o->cpOrderId = $args['out_trade_no'];                                  # 订单编号(龙游)
        $o->status = ($args["trade_status"] == "TRADE_SUCCESS") ? 1 : 2;        # 订单状态()
        $uid = $exts[0];
        $o->uid = substr($uid, strpos($uid, '-') + 1);                          # 玩家uid
        $o->amount = $args['total_amount'] * 100;                               # 支付金额, 游戏后台单位是分
        $o->callbackInfo = $args['passback_params'];                            # 透传参数, uid-uc,zoneid,cpOrderId
        $o->sdk_orderid = $args['trade_no'];                                    # 支付宝订单id
        $o->otherInfo = $args['buyer_logon_id'];                                # 支付宝登录账户号
        return $o;
    }

    /**
     * 解析微信通知
     * @param type $args
     * @return \loyalsoft\pay\OrderNotice
     */
    public static function Parse_weixinpayOrder($args) {
        $o = new OrderNotice();
        $exts = explode(',', urldecode($args['attach']));                       # 透传参数

        $o->channel = "soft";                                                   # 渠道代码zfb?
        $o->cpOrderId = $args['out_trade_no'];                                  # 订单编号(龙游)
        $o->status = ($args["result_code"] == "SUCCESS") ? 1 : 2;               # 订单状态()
        $uid = $exts[0];
        $o->uid = substr($uid, strpos($uid, '-') + 1);                          # 玩家uid
        $o->amount = $args['total_fee'];                                        # 支付金额, 游戏后台单位是分
        $o->callbackInfo = $args['attach'];                                     # 透传参数, uid-uc,zoneid,cpOrderId
        $o->sdk_orderid = $args['transaction_id'];                              # 微信订单id
        $o->otherInfo = $args['time_end'];                                      # 结束时间
        return $o;
    }

    /**
     * 解析应用宝充值通知
     * @param array $args
     */
    public static function Parse_yybOrder($args) {
        $o = new OrderNotice();
        $o->channel = "yyb";                                                    # 渠道代码
        $o->cpOrderId = $args['orderId'];                                       # 订单编号
        $o->status = ($args["status"] == "1") ? 1 : 2;                          # 订单状态(易接SDK返回值: 1/成功,其他失败)
        $o->uid = $args['uid']; // openid                                       # 玩家uid
        $o->amount = $args['amount'] * 100;                                     # 支付金额, 游戏后台统一单位是分
        $o->callbackInfo = $args['extReserved'];                                # 透传参数, uid-uc,zoneid,cpOrderId
        $o->otherInfo = $args['pf'];                                            # 手Qor微信的平台串
        return $o;
    }

    /**
     * 解析360充值通知
     */
    public static function Parse_360Order($args) {
        $exts = explode(',', $args['app_ext1']);
        $o = new OrderNotice();
        $o->channel = 'qihoo360';
        if (isset($args['app_order_id'])) {
            $o->cpOrderId = $args['app_order_id'];
        } else {
            $o->cpOrderId = $exts[2];                      # 第三个参数是cpOrderId
        }
        $o->sdk_orderid = $args['order_id'];
        $o->status = ($args['gateway_flag'] == 'success') ? 1 : 2;
        $o->uid = $args['app_uid'];
        $o->amount = $args['amount'];                                           # 360通知的单位是分,与后台一致
        $o->callbackInfo = $args['app_ext1'];
        $o->otherInfo = $args['user_id'];
        return $o;
    }

    /**
     * 解析vivo充值通知接口
     */
    public static function Parse_vivoOrder($args) {
        $o = new OrderNotice();
        $o->channel = 'vivo';
        $o->cpOrderId = $args['cpOrderNumber'];
        $o->sdk_orderid = $args['orderNumber'];
        $o->status = ($args['tradeStatus'] == '0000') ? 1 : 2;
        $o->uid = $args['uid'];
        $o->amount = $args['orderAmount'];                                      # vivo通知的单位是分, 与游戏后台一致
        $o->callbackInfo = $args['extInfo'];
        $o->otherInfo = 'payTime:' . $args['payTime'];
        return $o;
    }

    /**
     * 解析联想支付通知
     * @param type $args
     */
    public static function Parse_lenovo($args) {
//        var_dump($args);
        $exts = explode(',', $args['cpprivate']);
        $o = new OrderNotice();
        $o->channel = 'lenovo';
        $o->cpOrderId = $args['exorderno'];
        $o->sdk_orderid = $args['transid'];
        $o->status = ($args['result'] == 0) ? 1 : 2;
        $o->uid = $exts[0];
        $o->amount = $args['money'];
        $o->callbackInfo = $args['cpprivate'];
        $o->otherInfo = 'payType:' . $args['paytype'];
        return $o;
    }

    /**
     * 解析金立支付通知
     * @param type $args
     */
    public static function Parse_gionee($args) {
//        var_dump($args);
        $exts = explode(',', $args['ext_info']);     # 透传参数
        $o = new OrderNotice();
        $o->channel = 'gionee';
        $o->cpOrderId = $args['out_order_no'];
//        $o->sdk_orderid = $args['transid'];        # 金立订单只在创建的时候返回,通知的时候没有╭(╯^╰)╮
        $o->status = 1;                              # 金立后台只将支付成功的订单进行返回，未成功订单不会有通知
        $o->uid = $exts[0];
        $o->amount = $args['deal_price'] * 100;                                 # 金立后台单位是元, 游戏后台单位是分
        $o->callbackInfo = $args['ext_info'];
//        $o->otherInfo = '';                        #
        return $o;
    }

    /**
     * 解析百度支付通知
     * @param type $args
     */
    public static function Parse_Baidu($args) {
//        var_dump($args);

        $o = new OrderNotice();
        $o->channel = 'baidu';
        $o->cpOrderId = $args['CooperatorOrderSerial'];                         # CP 订单号
        $o->sdk_orderid = $args['OrderSerial'];                                 # SDK订单号
        $Contents = json_decode(base64_decode(urldecode($args['Content'])));    # 数据结构
        $o->status = $Contents->OrderStatus == 1 ? 1 : 2;                       # 0 失败, 1 成功
        $o->uid = $Contents->UID;                                               # UID
        $o->amount = $Contents->OrderMoney * 100;                               # 百度后台单位是元, 游戏后台单位是分
        $o->callbackInfo = $Contents->ExtInfo;                                  # 透传参数
        $o->otherInfo = '银行到账时间:' . $Contents->BankDateTime                # 其他信息
                . ' 代金券金额:' . $Contents->VoucherMoney;                      #
        return $o;
    }

    /**
     * 解析三星支付通知
     * @param type $args
     */
    public static function Parse_samsung($args) {
        $exts = explode(',', $args['cpprivate']);
        $o = new OrderNotice();
        $o->channel = 'samsung';
        if (isset($args['cporderid'])) {
            $o->cpOrderId = $args['cporderid'];
        } else {
            $o->cpOrderId = $exts[2];                                           // uid,zoneid,cporderid
        }
        $o->sdk_orderid = $args['transid'];                                     // 平台流水号
        $o->status = ($args['result'] == 0) ? 1 : 2;
        $o->uid = $args['appuserid'];
        $o->amount = $args['money'] * 100;                                      // float 单位:元, Ps.游戏后台是分
        $o->callbackInfo = $args['cpprivate'];
        $o->otherInfo = 'transtype:' . $args['transtype'];                      // 交易类型
        return $o;
    }

    /**
     * 解析小七手游支付通知
     * @param type $args
     */
    public static function Parse_x7sy($args) {
        $exts = explode(',', $args['extends_info_data']);
        $o = new OrderNotice();
        $o->channel = 'x7sy';
        if (isset($args['game_orderid'])) {                                     // cpOrder
            $o->cpOrderId = $args['game_orderid'];
        } else {
            $o->cpOrderId = $exts[2];                                           // uid,zoneid,cporderid
        }
        $o->sdk_orderid = $args['xiao7_goid'];                                  // 渠道流水号
        $o->status = 1; //($args['result'] == 0) ? 1 : 2;                       // 只要通知就是成功,不成功的不通知
        $o->uid = $args['guid'];
        $o->amount = $args['pay_price'] * 100;                                      // float 单位:元, Ps.游戏后台是分
//        $o->callbackInfo = $args['cpprivate'];
//        $o->otherInfo = 'transtype:' . $args['transtype'];                      // 交易类型
        return $o;
    }

}
