<?php

namespace loyalsoft;

require_once __DIR__ . '/../service_call/pay/official/pay_op.php';              # 封装渠道支付模块的操作

/**
 * 付费、游戏内消费相关处理
 * 全部动态交易数据需要保存到db作为[存根]
 * @version <br/>
 *          6.0.0 第六版: 引入currency字段, 增加出海结算支持.   2022.11
 *          5.0.0 第五版: 全部动态交易数据存入mysql.     2021.11
 *          4.0.0 第四版: 言灵世界 商城模块.    2020.08
 *          2.2.0 第三版: 独立的游戏币<元宝>, 面向多渠道的充值模式, 拉起充值成功后, 给玩家发放元宝. 游戏内部消费元宝,钻石和金币.可以用元宝购买金币和钻石.这一版在上面的PayProc中 * 2015年9月23日 <br/>
 *          2.1.0 mn_pay mn_AddUserCash ... 以 mn_ 打头的函数是第二版, 修改为伪托管模式,除了充值的时候跟腾讯通讯,其余时间自己管理游戏币:钻石. * 2015年7月23日 <br/>
 *          2.0.1 m_pay m_AddUserCash ... 以 m_ 打头的函数是第一版, 完全按照应用宝官方要求托管游戏币的模式开发的.  * 2015年4月23日 <br/>
 *          1.0.0 Created at 2016-4-20. by --gwang <br/>
 * @author gwang (mail@wanggangzero.cn)
 * @copyright © 2016-4-20, SJZ LoyalSoft Corporation & gwang. All rights reserved.
 */
class PayProc {

    const orderTab = 'tpl_order_tab';

    /**
     * 逻辑分发
     * 所有的Proc中必须有这样一个方法
     */
    public static function procMain() {
        switch (req()->cmd) {
            // 支付相关的活动
            case CmdCode::cmd_pay_getfirstpaygift:                              # 8802 领取首充礼包
                return PayProc::m_GetFirstPayGift();
// 游戏内二级货币消费
            case CmdCode::cmd_mpay_pay:                                         # 8807 消费..
                return self::m_pay();                                           # ::==> 购买普通商城物品

            case CmdCode::cmd_mpay_buyDynamic:                                  # 8809 购买动态商城物品
                return self::m_pay_buyDynamic();
            case CmdCode::cmd_mpay_getDynamic:                                  # 8810 刷新神秘商城物品
                return self::m_pay_getDynamic();

// 充值消费
            case CmdCode::cmd_mpay_get_balance:                                 # 8808 刷新账号余额
                return self::m_refreshChargeOrders();                           # ::==> 刷新订单-领取充值金额
            case CmdCode::cmd_mpay_selfCheckOrders:                             # 8811 自助检查异常订单
                return self::selfhelpCheckOrders();
            case CmdCode::cmd_mpay_getPayRecords:                               # 8812 查询订单记录
                return self::GetPayRecoreds();
            case CmdCode::cmd_mpay_PayDeliverGoods:                             # 8813 查询订单并发货
                return self::PayDeliverGoods();
            case CmdCode::cmd_mpay_UserRechargeDrawPrize:                       # 8814 充值领奖励 2022.10
                return self::UserRechargeDrawPrize();
            case CmdCode::cmd_mpay_NewFirstRecharge:                            # 8815 新首充功能 2022.10
                return self::NewFirstRecharge();
            default:
                return Resp::err(ErrCode::cmd_err);
        }
    }

    static $retArr;

    /**
     * 8815 新首冲功能5点前不能领取奖励,则该请求只是为了首充开发界面时获得最新时间戳
     */
    static function NewFirstRecharge() {
        UserProc::updateUserInfo();
        return Resp::ok(array(
                    "ret" => 'true',
        ));
    }

    /**
     * [8814]领取奖励 (新版2021)
     */
    static function UserRechargeDrawPrize() {
        list($type, $typeId) = req()->paras;
        $user = ctx();

        self::$retArr = array();

        switch ($type) {
            case Enum_Recharge::FirstRecharge://首冲
                my_Assert($user->pay->firstRechage == 0, ErrCode::shop_firstRechargeNotRepeat);

                StoreProc::AddMultiItemInStore(GameConfig::globalsettings()->firstRechargePrizes);
                $user->pay->firstRechage = 1;
                self::$retArr[] = GameConfig::globalsettings()->firstRechargePrizes;
                break;
            case Enum_Recharge::DaliySpecialPackages://每日特惠
                my_Assert(!in_array($typeId, $user->shopdata->daliySpecialPackages), ErrCode::shop_daliySpecialRewardNotRepeat);

                $mo = GameConfig::shop_limit_getItem($typeId);
                my_Assert($mo != null, ErrCode::err_const_no);
                if ($mo->price != 0) {//购买60元7天特惠，则不是免费的礼包现在也可以领取。这里校验一下
                    //my_Assert($user->shopdata->daliySpecial_ts!= 0, ErrCode::shop_daliySpecialRewardNotRepeat);
                    $ts = $user->shopdata->daliySpecial_ts + 7 * 24 * 60 * 60;
                    my_Assert(now() < $ts, ErrCode::shop_daliySpecialRewardNotRepeat);
                }
                $itemid = explode(',', $mo->reward)[0];
                $itemMO = GameConfig::item_package_getItem($itemid);
                my_Assert(null != $itemMO, ErrCode::err_const_no);
                StoreProc::AddMultiItemInStore($itemMO->contents);
                self::$retArr[] = $itemMO->contents;

                $shopdata = new Info_UserShop(ctx()->shopdata);
                $shopdata->daliySpecialPackages[] = $typeId;
                ctx()->shopdata = $shopdata;
                break;
            case Enum_Recharge::RechargeRebate://充值返利
                $mo = GameConfig::rechargeRebate_getItem(3, $typeId);
                my_Assert($mo != null, ErrCode::err_const_no);
                my_Assert($user->baseInfo->charge_amt >= $mo->rmb, ErrCode::shop_RechargeRebateRmbNotEnough);
                my_Assert(!in_array($typeId, $user->shopdata->rechargeRebateRewardsList), ErrCode::shop_RechargeRebateRewardNotRepeat);

                StoreProc::AddMultiItemInStore($mo->rewards);
                self::$retArr[] = $mo->rewards;
                break;
            case Enum_Recharge::LimitBuy://限购中免费礼包领取
                $packageCfg = GameConfig::shop_limit_getItem($typeId);
                my_Assert(null != $packageCfg, ErrCode::err_const_no);
                my_Assert($packageCfg->price == 0, ErrCode::shop_limit_NotFree);

                self::checklimitBuyRecharge($typeId);
                break;
            case Enum_Recharge::Accumulate:                                     # 累充, gwang 2022.10.18
//                list($amount, $day) = explode('-', $typeId);                      # 拆分key1,key2
//                $cfg = GameConfig::shop_accumulating_getItem($amount, $day);      # 配置对象
//                my_Assert(null != $cfg, ErrCode::err_const_no);                   # 防御null
//
//                $acc = new Ins_Accumulate($user->shopdata->shopAccumulateData);   # 累充对象
//                my_Assert(!$acc->IsDrawed($amount, $day), ErrCode::active_hasgetted); # 防御: 已经领取
//                my_Assert($user->baseInfo->rechargeFun_amt >= $cfg->amount, "累充金额不足!"); # 校验: 金额
//                my_Assert($acc->EndDay() >= tsDay(), "领取时间已过!");             # 校验: 时间
//                StoreProc::AddMultiItemInStore($cfg->goods);                      # 发放奖品
//                $user->shopdata->shopAccumulateData = $acc->SetDrawd($amount, $day); # 更新数据
//                self::$retArr[] = $cfg->goods;
                $mo = GameConfig::rechargeRebate_getItem(Enum_Recharge::Accumulate, $typeId);
                my_Assert($mo != null, ErrCode::err_const_no);
                my_Assert($user->baseInfo->charge_amt >= $mo->rmb, ErrCode::shop_RechargeRebateRmbNotEnough);
                my_Assert(!in_array($typeId, $user->shopdata->rechargeRebateRewardsList), ErrCode::shop_RechargeRebateRewardNotRepeat);
                $user->shopdata->rechargeRebateRewardsList[] = $typeId;

                StoreProc::AddMultiItemInStore($mo->rewards);
                self::$retArr[] = $mo->rewards;

                break;
            case Enum_Recharge::FirstRecharge_new:
                $mo = GameConfig::shop_accumulating_getItem($typeId);
                my_Assert(null != $mo, ErrCode::err_const_no);
                $shopdata = new Info_UserShop(ctx()->shopdata);
                $amount = $mo->amount;
                if (!StlUtil::dictHasProperty($shopdata->fRechargeRecord, $amount)) {
                    $shopdata->fRechargeRecord->$amount = array();
                }
                my_Assert(!in_array($typeId, $shopdata->fRechargeRecord->$amount), ErrCode::active_FirstRechargeRewardRepeat);
                $shopdata->fRechargeRecord->$amount[] = $typeId;
                StoreProc::AddMultiItemInStore($mo->goods);                      # 发放奖品
                ctx()->shopdata = $shopdata;
                self::$retArr[] = $mo->goods;

                break;
            case Enum_Recharge::DayAccumulateRecharge:                          #每周累计金额奖励
                $mo = GameConfig::rechargeRebate_getItem($type, $typeId);
                my_Assert($mo != null, ErrCode::err_const_no);

                my_Assert($user->shopdata->dayRechargeAmt >= $mo->rmb, ErrCode::shop_RechargeRebateRmbNotEnough);
                my_Assert(!in_array($typeId, $user->shopdata->dayRechargeReceived), ErrCode::shop_RechargeRebateRewardNotRepeat);
                $user->shopdata->dayRechargeReceived[] = $typeId;

//                if ($rechargeType == 1) {
//                    my_Assert($user->shopdata->dayRechargeAmt >= $mo->rmb, ErrCode::shop_RechargeRebateRmbNotEnough);
//                    my_Assert(!in_array($rmb, $user->shopdata->dayRechargeReceived), ErrCode::shop_RechargeRebateRewardNotRepeat);
//                    $user->shopdata->dayRechargeReceived[] = $rmb;
//                } else if($rechargeType == 2){
//                    my_Assert($user->shopdata->weekRechargeAmt >= $mo->rmb, ErrCode::shop_RechargeRebateRmbNotEnough);
//                    my_Assert(!in_array($rmb, $user->shopdata->weekRechargeReceived), ErrCode::shop_RechargeRebateRewardNotRepeat);
//                    $user->shopdata->weekRechargeReceived[] = $rmb;
//                }

                StoreProc::AddMultiItemInStore($mo->rewards);
                self::$retArr[] = $mo->rewards;

                break;
            case Enum_Recharge::WeekAccumulateRecharge:                         #每周累计金额奖励
                $mo = GameConfig::rechargeRebate_getItem($type, $typeId);
                my_Assert($mo != null, ErrCode::err_const_no);

                my_Assert($user->shopdata->weekRechargeAmt >= $mo->rmb, ErrCode::shop_RechargeRebateRmbNotEnough);
                my_Assert(!in_array($typeId, $user->shopdata->weekRechargeReceived), ErrCode::shop_RechargeRebateRewardNotRepeat);
                $user->shopdata->weekRechargeReceived[] = $typeId;

                StoreProc::AddMultiItemInStore($mo->rewards);
                self::$retArr[] = $mo->rewards;

                break;

            default:
                break;
        }

        ctx($user);

        UserProc::updateUserInfo();
        return Resp::ok(array(
                    "ret" => self::$retArr,
                    "pay" => $user->pay,
                    "shopdata" => ctx()->shopdata,
                    "base" => $user->baseInfo,
                    "store" => $user->store,
        ));
    }

    /**
     * 限购礼包--终身礼包--套装礼包--校验
     * @param type $packageId
     */
    private static function checklimitBuyRecharge($packageId) {                        # 参数; 礼包id
        $shopdata = new Info_UserShop(ctx()->shopdata);
        $packageCfg = GameConfig::shop_limit_getItem($packageId);
        my_Assert(null != $packageCfg, ErrCode::err_const_no);

        $arr = array();
        if ($packageCfg->goodsType == Enum_Recharge::LifelongGift) {
            $shopdata->lifelongGiftReceived[] = $packageId;
            $arr = $shopdata->lifelongGiftReceived;
        } elseif ($packageCfg->goodsType == Enum_Recharge::SuitGift) {
            $ts = now() - $shopdata->suitGiftStartTs;
            my_Assert($ts <= $packageCfg->limit_ts, ErrCode::shop_limit_TsMax);    # 校验时间

            $shopdata->suitGiftReceived[] = $packageId;
            $arr = $shopdata->suitGiftReceived;
        } else {
            switch ((int) $packageCfg->subType) {
                case 1:
                    $shopdata->purchasedDailyLimitPackages[] = $packageId;
                    $arr = $shopdata->purchasedDailyLimitPackages;
                    break;
                case 2:
                    $shopdata->purchasedWeeklyLimitPackages[] = $packageId;
                    $arr = $shopdata->purchasedWeeklyLimitPackages;
                    break;
                case 3:
                    $shopdata->purchasedMonthlyLimitPackages[] = $packageId;
                    $arr = $shopdata->purchasedMonthlyLimitPackages;
                    break;
                default:
                    Err(ErrCode::err_innerfault);
            }
        }


        $hasN = count(array_filter($arr, function ($val)use ($packageId) {      # 计数:筛选条件
                    return $val == $packageId;
                }));
        my_Assert($hasN <= $packageCfg->limit_num, ErrCode::shop_limit_max);    # 校验购买数量
        $itemid = explode(',', $packageCfg->reward)[0];                         # 奖励礼包Id
        $itemMO = GameConfig::item_package_getItem($itemid);
        my_Assert(null != $itemMO, ErrCode::err_const_no);
        $err = StoreProc::AddMultiItemInStore($itemMO->contents);               # 发放奖励
        self::$retArr[] = $itemMO->contents;
        my_Assert(ErrCode::ok == $err, $err);
        ctx()->shopdata = $shopdata;                                            # 回写数据
    }

    /**
     * [8813] 充值发货 (新版2021)
     */
    static function PayDeliverGoods() {
        list($cpOrderId) = req()->paras;

        $result = pay_op::CheckAndDrawOrder(req()->uid, $cpOrderId, array(new PayProc, 'distributePayGoods'));
        my_Assert($result->err == 0, ErrCode::pay_fail);

        $user = ctx();
        NormalEventProc::OnPaySuccess();
        UserProc::updateUserInfo();                                             # 回写玩家数据
        return Resp::ok(array(
                    "ret" => self::$retArr,
                    "pay" => $user->pay,
                    "base" => $user->baseInfo,
                    "shopdata" => $user->shopdata,
                    "store" => $user->store,
        ));
    }

    //发货
    static function distributePayGoods($order = null) {
        my_Assert($order->product_id != null, ErrCode::pay_order_product_id);
        $user = ctx();

        self::$retArr = array();
        if ($order->product_id >= 6 && $order->product_id <= 1000) {//充值表
            $mo = GameConfig::recharge_getItem($order->product_id);
            my_Assert($mo != null, ErrCode::err_const_no);

            if (!StlUtil::dictHasProperty($user->shopdata, 'rechargeRecordList')) {
                $user->shopdata->rechargeRecordList = array();
            }

            $cash = $mo->rmd * 10;
            if (!in_array($order->product_id, $user->shopdata->rechargeRecordList)) {
                $cash = $mo->rmd * 10 * $mo->firstDouble;
                $user->shopdata->rechargeRecordList[] = $order->product_id;
            }
            $user->base()->Add_Cash($cash);
            self::$retArr[] = "2," . $cash;
        } elseif ($order->product_id >= 801001 && $order->product_id <= 803999) {//限购
            self::checklimitBuyRecharge($order->product_id);

            $mo = GameConfig::shop_limit_getItem($order->product_id);
            if ($mo->subType == 1) {
                $user->shopdata->dayRechargeAmt += $order->amount;
            } else if ($mo->subType == 2) {
                $user->shopdata->weekRechargeAmt += $order->amount;
            }
        } elseif ($order->product_id >= 804001 && $order->product_id <= 804999) {//每日特惠
            $mo = GameConfig::shop_limit_getItem($order->product_id);
            my_Assert($mo != null, ErrCode::err_const_no);
            if ($mo->price == 60) {
                $user->shopdata->daliySpecial_ts = now();
            } else {
                $itemid = explode(',', $mo->reward)[0];
                $itemMO = GameConfig::item_package_getItem($itemid);
                my_Assert(null != $itemMO, ErrCode::err_const_no);
                StoreProc::AddMultiItemInStore($itemMO->contents);
                $user->shopdata->daliySpecialPackages[] = $mo->typeId;
                self::$retArr[] = $itemMO->contents;
            }
        } elseif ($order->product_id >= 805001 && $order->product_id <= 805999) {//限时
            $mo = GameConfig::shop_limit_getItem($order->product_id);
            my_Assert($mo != null, ErrCode::err_const_no);
            my_Assert(!in_array($order->product_id, $user->shopdata->limitTsActiveRewardsList), ErrCode::err_const_no);

            $user->shopdata->limitTsActiveRewardsList[] = $mo->typeId;
            $itemid = explode(',', $mo->reward)[0];
            $itemMO = GameConfig::item_package_getItem($itemid);
            my_Assert(null != $itemMO, ErrCode::err_const_no);
            StoreProc::AddMultiItemInStore($itemMO->contents); //领取奖励
            self::$retArr[] = $itemMO->contents;
        } elseif ($order->product_id >= 806001 && $order->product_id <= 806999) {//首充【2022-10-19新的首充功能】
            $mo = GameConfig::shop_accumulating_getItem($order->product_id);
            my_Assert($mo != null, ErrCode::err_const_no);
            $shopdata = new Info_UserShop(ctx()->shopdata);
            $amount = $mo->amount;
            if (!StlUtil::dictHasProperty($shopdata->fRechargeTime, $amount)) {
                $shopdata->fRechargeTime->$amount = TimeUtil::tsDay();
            }
            $cost = 0;
            $dic = GameConfig::shop_accumulating();
            foreach ($dic as $k => $item) {
                if ($cost <= $item->amount) {
                    $cost = $item->amount;
                }
            }
            if ($cost <= $amount && $shopdata->suitGiftStartTs == 0) {
                $shopdata->suitGiftStartTs = now();
            }
            ctx()->shopdata = $shopdata;
            //self::$retArr[] = $mo->goods;
        } elseif ($order->product_id >= 807001 && $order->product_id <= 807999) {//终身礼包
            self::checklimitBuyRecharge($order->product_id);
        } elseif ($order->product_id >= 808001 && $order->product_id <= 808999) {//套装礼包
            self::checklimitBuyRecharge($order->product_id);
        } elseif ($order->product_id >= 901001 && $order->product_id <= 999999) {//月卡
            $shopdata = new Info_UserShop(ctx()->shopdata);
            $packageCfg = GameConfig::shop_monthVIP_getItem($order->product_id);
            my_Assert(null != $packageCfg, ErrCode::err_const_no);
            if ($packageCfg->subType == 4) {
                my_Assert($shopdata->monthlyVIP1_ts + $packageCfg->ExpireTs * 3600 * 24 < now(), ErrCode::shop_monthlyvip_buyed);
            } elseif ($packageCfg->subType == 5) {
                my_Assert($shopdata->monthlyVIP2_ts + $packageCfg->ExpireTs * 3600 * 24 < now(), ErrCode::shop_monthlyvip_buyed);
            }
            $err = StoreProc::AddMultiItemInStore($packageCfg->pri_reward);     # 发放一次性奖励
            self::$retArr[] = $packageCfg->pri_reward;
            my_Assert(ErrCode::ok == $err, $err);
            if ($packageCfg->subType == 4) {
                $shopdata->monthlyVIP1_ts = 3600 * 24 * (totalDays() + 1) - 1;
            } elseif ($packageCfg->subType == 5) {
                $shopdata->monthlyVIP2_ts = 3600 * 24 * (totalDays() + 1) - 1;
            }

            EmailProc::SendMonthlyVIPDailyReward(req()->zoneid, req()->uid, $packageCfg->name, $packageCfg->daily_reward);

            ctx()->shopdata = $shopdata;
        }

        $user->baseInfo->charge_amt += $order->amount;
        ctx($user);

        return true;
    }

    static function suitGiftCheck() {
        $shopdata = new Info_UserShop(ctx()->shopdata);

        $cost = 0;
        $dic = GameConfig::shop_accumulating();
        foreach ($dic as $k => $item) {
            if ($cost <= $item->amount) {
                $cost = $item->amount;
            }
        }

        if (StlUtil::dictHasProperty($shopdata->fRechargeTime, $cost)) {
            if ($shopdata->suitGiftStartTs == 0) {
                $shopdata->suitGiftStartTs = now();
            }
        } else {
            $shopdata->suitGiftStartTs = 0;
        }

        ctx()->shopdata = $shopdata;
    }

    static function checkAmount($order) {
        my_Assert($order->product_id != null, ErrCode::pay_order_product_id);
        if ($order->product_id >= 6 && $order->product_id <= 1000) {//充值表
            $mo = GameConfig::recharge_getItem($order->product_id);
            my_Assert($mo != null, ErrCode::err_const_no);
            my_Assert($order->amount == $mo->rmd, ErrCode::pay_price_err);
        } elseif ($order->product_id >= 801001 && $order->product_id <= 801999) {//限购
            //该功能暂时没有开发
        } elseif ($order->product_id >= 804001 && $order->product_id <= 804999) {//每日特惠
            $mo = GameConfig::shop_limit_getItem($order->product_id);
            my_Assert($mo->price == $order->amount, ErrCode::pay_price_err);
        } elseif ($order->product_id >= 805001 && $order->product_id <= 805999) {//限时
            //该功能暂时没有开发
        } elseif ($order->product_id >= 901001 && $order->product_id <= 999999) {//月卡
            $packageCfg = GameConfig::shop_monthVIP_getItem($order->product_id);
            my_Assert(null != $packageCfg, ErrCode::err_const_no);
            my_Assert($packageCfg->price == $order->amount, ErrCode::pay_price_err);
        }

        return true;
    }

    /**
     * 礼包有了的第一次登录记录
     */
    static function SuitGiftTsRecord() {
        $shopdata = new Info_UserShop(ctx()->shopdata);
        if (!StlUtil::dictHasProperty($shopdata, 'suitGiftStartTs')) {
            $shopdata->suitGiftStartTs = 0;
        }

        if ($shopdata->suitGiftStartTs == 0) {
            $shopdata->suitGiftStartTs = now();
        }
        ctx()->shopdata = $shopdata;
    }

    /**
     * 8812 查询充值记录
     */
    static function GetPayRecoreds() {
        $uid = req()->uid;
        $table = "tpl_order_tab";
        $arr = daoInst()->select(" cpOrderId as '订单' ,product_name as '道具',amount as '金额' ,from_unixtime(order_ts) as '时间' ")->from($table)
                ->where("uid")->eq($uid)
                ->andWhere("status")->eq(1)
                ->fetchall();
        return Resp::ok($arr);
    }

//
// <editor-fold defaultstate="collapsed" desc="  移动支付 - 刷新订单  ">

    /**
     *  刷新充值订单(领取充值结果)
     */
    public static function m_refreshChargeOrders() {
# 客户端参数解析
        $uid = req()->uid;                                                      # userID
        $zoneid = req()->zoneid;                                                # 分区Id
        if (count(req()->paras) <= 0) {                                         # 参数为空, 执行自检逻辑
            return self::selfhelpCheckOrders();
        }
        $cpOrderId = req()->paras[0];                                           # 后台订单编号
        if (!$uid || ($zoneid < 1) || strlen($cpOrderId) != 16) {               # 订单编号长16位
            return Resp::err(ErrCode::paras_err);
        }
        $order = daoInst()->select()->from(self::orderTab)                      # 取订单数据
                        ->where('cpOrderId')->eq($cpOrderId)
                        ->limit(1)->fetch();
        if (!$order) {
//            var_dump($order);
            CLog::pay(' 订单不存在! ' . $cpOrderId);
            return Resp::err(ErrCode::pay_order_no);
        }
        if (false === strpos($uid, $order->uid)) {                              # UID不符
            return Resp::err(ErrCode::pay_order_uid);
        }

        if ($order->status != 1) {
            CLog::pay(' 订单尚未完成支付!');
            return Resp::err(ErrCode::pay_order_paystatus);
        }
        if ($order->drawed_ts > 0) {                                             # 定单已经发过货了
            CLog::pay(' 订单重复请求发货!' . $cpOrderId);
            return Resp::err(ErrCode::pay_order_drawed);
        }
        // 准备发货
        $product_id = $order->product_id;
        $product_count = $order->product_count;
        $typid = substr("$product_id", 0, 3);                                   # 提取商品编号前缀
        switch ($typid) {
            case '802':                                                         # 神秘商城物品
                $item = GameConfig::secretshop_typeId_getItem($product_id);
                break;
            case '801':                                                         # 商城物品
                $item = GameConfig::shop_getItem($product_id);
                break;
            default :
                return Resp::err(ErrCode::pay_systembusy_err);
        }
        my_Assert(isset($item), ErrCode::pay_shopItem_cosnt_goods_err);

        if ($item->pricetype != 0) {
            CLog::pay(" 道具付费类型异常:" . $product_id);
            return Resp::err(ErrCode::pay_m_type_err);
        }
        for ($i = 0; $i < $product_count; $i++) {                                       # 默认为1,还没有设计为n的情况
            StoreProc::AddMultiItemInStore($item->goods, 5);                      # 发货
        }
        $n = daoInst()->update(self::orderTab)
                ->data(array('drawed_ts' => now()))
                ->where('cpOrderId')->eq($cpOrderId)
                ->exec();
        my_Assert($n > 0, ErrCode::err_db);                                             # 数据库操作失败

        ctx()->baseInfo->charge_amt += $order->amount;                   # 历史充值记录(单位分)
        UserProc::updateUserInfo();                                                     # 更新玩家数据信息
        Event::trigger('pay', array('amt' => $order->amount));                          # 触发充值事件
        CLog::pay("订单发货成功: $cpOrderId");
        return Resp::ok(# 返回
                        array('cash' => ctx()->baseInfo->cash, #         # 直接将游戏币的最新值返回给客户端
                            'charge_amt' => ctx()->baseInfo->charge_amt, # 充值总记录
                            'store' => ctx()->store, #                   # 背包
                            'goods' => $item->goods, #                                  # 发货内容
                            'count' => $product_count, #                                # 发货数量
                        )
        );
    }

    /**
     *  检查删档内测订单
     */
    static function checkDeltest() {
        $uid = req()->uid;
        if (ctx()->privateState->deltest == 1) {
            $orders = daoInst()->select()->from('tpl_order_tab_deltest')
                    ->where('uid')->eq($uid)
                    ->andwhere('status')->eq(1)
                    ->fetchall();
            if (count($orders) > 0) {                                           # 有充值记录
                foreach ($orders as $order) {
                    // 翻倍发放砖石
                    isEditor() and $order = new pay\dbOrder();
                    $rmb = intval($order->amount / 100);                        # 计算充值金额(元)
                    EmailProc::SendDelTestMail(req()->zoneid, $uid, $rmb);

                    CLog::pay(req()->uid . '发送删档内侧补偿邮件' . $order->cpOrderId);
                }
            }
            ctx()->privateState->deltest = 0;
        }
//        CLog::pay('删档内测补偿检查');
    }

    /**
     * 检查异常订单, 补发道具
     */
    public static function selfhelpCheckOrders() {
        $uid = req()->uid;
        $orders = daoInst()->select()
                ->from('tpl_order_tab')
                ->where('uid')->eq($uid)
                ->andWhere('status')->eq(1)
                ->andWhere('drawed_ts')->le(0)
                ->fetchAll();
        if (count($orders) > 0) {
            foreach ($orders as $order) {
                // 准备补发
                $product_id = $order->product_id;
                $product_count = $order->product_count;
                $typid = substr("$product_id", 0, 3);                           # 提取商品编号前缀
                $goods = '';
                switch ($typid) {
                    case '802':                                                 # 神秘商城物品
                        $item = GameConfig::secretshop_typeId_getItem($product_id);
                        break;
                    case '801':                                                 # 商城物品
                        $item = GameConfig::shop_getItem($product_id);
                        break;
                    default :
                        return Resp::err(ErrCode::pay_systembusy_err);
                }
                if (!$item) {
                    return Resp::err(ErrCode::pay_shopItem_cosnt_goods_err);
                }
                if ($item->pricetype != 0) {                                    # 并非人民币定价
                    CLog::pay(" 道具付费类型异常:" . $product_id);
                    return Resp::err(ErrCode::pay_m_type_err);
                }
                for ($i = 0; $i < $product_count; $i++) {                       # 默认为1,还没有设计为n的情况
                    StoreProc::AddMultiItemInStore($item->goods, 5);      # 发货
                }
                $goods .= $item->goods;
                $n = daoInst()->update(self::orderTab)                          # 更新订单状态
                        ->data(array('drawed_ts' => now()))
                        ->where('cpOrderId')->eq($order->cpOrderId)
                        ->exec();
                if (!$n) {                                                      # 影响条数应为1
                    CLog::pay(req()->uid . ' 登录补发订单失败 ' . $order->cpOrderId);
                    return Resp::err(ErrCode::err_db);              # 数据库操作失败
                }
                ctx()->baseInfo->charge_amt += $order->amount;             # 历史充值记录(单位分)
                UserProc::updateUserInfo();                                 # 回写玩家数据
                CLog::pay(req()->uid . ' 登录补发订单 ' . $order->cpOrderId);
            }
            return Resp::ok(# 返回
                            array('cash' => ctx()->baseInfo->cash, #       # 直接将游戏币的最新值返回给客户端
                                'store' => ctx()->store, #               # 背包
                                'goods' => $goods, #                                    # 发货内容
                                'count' => count($orders), #                            # 发货数量
                                'msg' => "找到并处理" . count($orders) . "条未发货订单."
            ));
        }
        return Resp::ok('ok');                                      # everything is ok!
    }

// </editor-fold>
//
// <editor-fold defaultstate="collapsed" desc="  移动支付 - 商城购买  ">

    /**
     *  8810 免费或利用【游戏内货币】获取神秘商城物品
     *  刷新规则: 根据玩家拥有的英雄、装备、道具等数据进行刷新。（因英雄、道具、装备数量不足以支撑该刷新规则，目前先按照随机刷新做，几率平等）
     */
    public static function m_pay_getDynamic() {
        $user = ctx();
        $userSecretshop = new Info_UserSecretshop($user->userSecretshop);
        // 参数提取
        $refreshType = req()->paras[0];                                          # 刷新类型(参数)0,不刷,1,免费刷,2,钻石刷
        switch ($refreshType) {
            case 1:                                                             # 免费刷
                if (now() < $userSecretshop->lastRefreshTs + glc()->secretshop_refresh_interval) { // 检查是否达到免费刷新时间了, 执行自动更新
                    return Resp::err(ErrCode::pay_secretshopt_freeRefresh_Time);
                }
                break;
            case 2:                                                             # 钻石刷
                if (glc()->secretshop_refresh_maxtimes <= $userSecretshop->refreshedTimes) { // 检查刷新次数, 已达上限, 返回错误信息
                    return Resp::err(ErrCode::pay_refresh_times);
                }                                                               # 可以继续刷新,
                $cishu = $userSecretshop->refreshedTimes + 1;                   # 下次
                $amt = GameConfig::secretshop_refresh_getItem($cishu)->price;
                if (!$user->base()->Consume_Cash($amt)) {                       # 扣除本次所需费用, 余额不足, 返回错误信息
                    return Resp::err(ErrCode::notenough_cash_msg);
                }
                $userSecretshop->refreshedTimes++;                              # 增加当天付费刷新计数
                break;
            case 0:                                                             # 不刷
            default :                                                           # 默认不刷
                // do nothing.
                break;
        }
        if ($refreshType != 0) {                                                   # 是否刷新
            $err = self::refreshDynamicShopItems($userSecretshop);        # 更新物品表
            if ($err) {
                return Resp::err($err);
            }
            $user->userSecretshop = $userSecretshop;
            ctx($user);
            UserProc::updateUserInfo();
        }
        // 返回最新物品表
        return Resp::ok(array(#                                                 # 成功后将最新的玩家数据返回给客户端
                    'gold' => $user->baseInfo->gold,
                    'tili' => $user->baseInfo->tili,
                    'cash' => $user->baseInfo->cash,
                    'uss' => $userSecretshop, #                                 # 当前神秘商城数据
        ));
    }

    /**
     * 更新神秘商城物品
     * @param Info_UserSecretshop $userSecretshop Description
     */
    private static function refreshDynamicShopItems(&$userSecretshop) {
        $userSecretshop->lastRefreshTs = now();
        // todo: 这里补完更新物品的函数,     //        第一版: 随机
        $userSecretshop->currentItems = ObjectInit();
        for ($i = 1; $i <= 3; $i++) {                                             # 3种类型的商品
            $arr = GameConfig::secretshop_goodsType_getItem($i);
            if (count($arr) > 0) {
                $err = self::Dice(GameConfig::secretshop_goodsType_getItem($i), 1, $userSecretshop); # 一个种类一次1个物品
                if ($err) {
                    return $err;
                }
            }
        }
        return ErrCode::ok;
    }

    /**
     * 投骰子
     * @param assoc_array $arr 奖池物品
     * @param int $number 提取数量
     * @return string itemid,num;itemid,num;...
     */
    private static function Dice($arr, $number, &$userSecretshop) {
        $max = 0;                                                               # 计算物品权重总和
        array_walk($arr, function ($value) use (&$max) {
            $max += $value->probability;
        });
        if (!$max) {                                                            # 配置数据有问题
            return ErrCode::err_const_no;
        }
        for ($i = 0; $i < $number; $i++) {
            $rnd = CommUtil::random(1, $max);                                   # 投骰子
            $start = 0;
            $rew = null;
            foreach ($arr as $item) {                                           # 循环判断落入那个物品上
                if (CommUtil::isPropertyExists($item, 'probability') //         #
                        && $start < $rnd && $rnd <= $start + $item->probability) { # 落入区间
                    $rew = $item;                                               # 记录物品
                    break;
                }
                $start += $item->probability;                                   # 继续判断是否落入下一物品的区间
            } # foreach end
            if (!$rew) {
                return ErrCode::lottery_noselecteditem;
            }
            $id = $rew->typeId;
            $userSecretshop->currentItems->$id = 0;
        } # for end
        return ErrCode::ok;
    }

    /**
     * 清理每日各种上限
     */
    private static function clearDailyLimits() {
        $userSecretshop = new Info_UserSecretshop(ctx()->userSecretshop);
        $userSecretshop->refreshedTimes = 0;
        ctx()->userSecretshop = $userSecretshop;
    }

    /**
     * [8809]【游戏内货币】购买神秘商城物品
     * 规则： 商城物品会刷新
     */
    public static function m_pay_buyDynamic() {
        $user = new Data_UserGame(ctx());
        $userSecretshop = new Info_UserSecretshop($user->userSecretshop);
        $itemId = req()->paras[0];                                              # 商品id (点一次购买一个)
        $num = 1;                                                               # 暂时固定为一次购买一个
        #
        my_Assert(CommUtil::isPropertyExists($userSecretshop->currentItems, $itemId), ErrCode::pay_secretshop_noitem_err);
        $cishu = $userSecretshop->currentItems->$itemId;                        # 购买次数
        my_Assert($cishu < glc()->secretshop_itembuy_maxtimes, ErrCode::pay_secretshop_buytimes); # 判断购买次数

        $shopItem = GameConfig::secretshop_typeId_getItem($itemId);             # 常量数据
        $amt = $shopItem->price * pow(2, $cishu);                               # 计算价格
        switch ($shopItem->pricetype) {
            case 1:
                my_Assert($user->base()->Consume_Cash($amt), ErrCode::notenough_cash_msg); # 扣除钻石
                break;
            case 2:
                my_Assert($user->base()->Consume_Gold($amt), ErrCode::notenough_gold_msg); # 扣除金币
                break;
            default :
                return Resp::err(ErrCode::pay_m_type_err);
        }
        // 道具解包/发货
        $err = self::expendSecretShopItem($shopItem, $num);                     # 发放商品

        if ($err != ErrCode::ok) {                                              # 发货失败
            return Resp::err($err);
        }
        $userSecretshop->currentItems->$itemId += 1;                            # 购买次数+1
        $user->userSecretshop = $userSecretshop;
        ctx($user);
        UserProc::updateUserInfo();                                             # 回写数据
//        StatProc::secretShopbuy($req->zoneid, $req->uid, $itemId, $num);        # 统计/监控数据
        return Resp::ok(array(#                                                 # 成功后将最新的玩家数据返回给客户端
                    'gold' => $user->baseInfo->gold,
                    'tili' => $user->baseInfo->tili,
                    'cash' => $user->baseInfo->cash,
                    'store' => $user->baseInfo->store, #                                  # 背包,(装备、碎片、。。)
                    'heros' => $user->baseInfo->heros #                                   # 角色
        ));
        //
    }

    /**
     * [8807]【游戏内货币】购买普通商城物品
     */
    public static function m_pay() {
        $user = ctx();                                          # user引用
        my_Assert(count(req()->paras) >= 3, ErrCode::parasnotenough_msg);       # 参数不足

        list($paytype, $itemId, $num) = req()->paras;                           # 付费类型, 1.钻石, 2.金币 ,道具ID ,数量, 默认为1
        my_Assert($num >= 1, ErrCode::paras_err);                               # 参数非法,
        $shopItem = GameConfig::shop_getItem($itemId);                          # 取商品的常量数据
        my_Assert(isset($shopItem), ErrCode::err_const_no);                     # 检测是否存在道具的常量数据
        my_Assert($shopItem->pricetype == $paytype, ErrCode::pay_price_err);    # 商品定价类型检查
        $amt = $shopItem->price;                                                # 道具价格（钻石）
        my_Assert($amt > 0, ErrCode::pay_price_err);                            # 商品定价数值检查
        $bDeal = false;                                                         # 成交标志位
        switch ($paytype) {                                                     # 1. 钻石, 2. 金币, other:非法
            case 1:                                                             # 钻石
                $bDeal = ctx()->base()->Consume_Cash($amt);     # 更新(扣除)玩家游戏币(钻石)余额
                my_Assert($bDeal, ErrCode::notenough_cash_msg);                 # 防范扣除失败
                break;
            case 2:                                                             # 金币
                $bDeal = $user->base()->Consume_Gold($amt * $num);        # 更新玩家金币余额
                my_Assert($bDeal, ErrCode::notenough_gold_msg);                 # 防范扣除失败
                break;
            default :                                                           # 未知的支付类型
                return Resp::err(ErrCode::pay_m_type_err);
        }

        my_Assert($bDeal, ErrCode::err_innerfault);                             # 交易失败
        $err = self::expendShopItem($shopItem, $num);                           # 发放商品(普通商城只有金币和体力)
        my_Assert(ErrCode::ok == $err, $err);                                   # 防范发货失败
        UserProc::updateUserInfo();                                             # 回写数据
//            StatProc::shopbuy($zoneid, $uid, $itemId, $num);                    # 统计/监控数据
        return Resp::ok(array(#                                                 # 成功后将最新的玩家数据返回给客户端
                    'gold' => $user->baseInfo->gold,
                    'tili' => $user->baseInfo->tili,
                    'cash' => $user->baseInfo->cash,
                    'store' => $user->store
        ));
    }

    /**
     * 解包商城物品并发货
     * @param sm_Shop $shopItem
     * @param int $num 数量
     */
    private static function expendShopItem($shopItem, $num) {
        for ($i = 0; $i < $num; $i++) {
            $err = StoreProc::AddMultiItemInStore($shopItem->goods, '商城');
            my_Assert(ErrCode::ok == $err, $err);
        }
        return ErrCode::ok;
    }

    /**
     * 道具解包并发货(神秘商城)
     * @param sm_secretshop $shopItem
     * @param type $num
     */
    private static function expendSecretShopItem($shopItem, $num) {
        for ($i = 0; $i < $num; $i++) {
            $err = StoreProc::AddMultiItemInStore($shopItem->goods, '神秘商城');
            if ($err) {
                return $err;
            }
        }
        return ErrCode::ok;
    }

// </editor-fold>
//
    //
// <editor-fold defaultstate="collapsed" desc="  支付活动 - 首付礼包">

    /**
     * [8802] 领取首付礼包
     */
    public static function m_GetFirstPayGift() {
        $itemId = glc()->FirstPay_ItemId;
        $privateState = ctx()->privateState;

        if (CommUtil::isPropertyExists($privateState, "firstPayGift") #
                && $privateState->firstPayGift) {                               # 如果已经领取首付礼包
            return Resp::err(ErrCode::pay_firstpaygetted);
        }
        my_Assert(ctx()->baseInfo->charge_amt > 0, ErrCode::pay_firstpayno_err);                            # 如果尚未完成首付

        $itemModel = GameConfig::shop_getItem($itemId);                         # 取商品常量
        if ($itemModel == null) {                                               # 检测首付礼包是否存在
            return Resp::err(ErrCode::err_const_no);
        }
        ctx()->privateState->firstPayGift = true;               # 设置首付标志
        StoreProc::AddMultiItemInStore($itemModel->goods);                      # 发放首付礼包到玩家仓库
        UserProc::updateUserInfo();                                             # 更新玩家数据
        return Resp::ok(array('itemid' => $itemId,
                    'rewardstr' => $itemModel->goods,
                    'store' => ctx()->store));                   # 回送成功信息
    }

// </editor-fold>
//
//
//
}
