* @version : HUOSDK 8.0 */ namespace huo\controller\pay; use huo\controller\agent\AgentCache; use huo\controller\common\Base; use huo\controller\conf\PaywayConf; use huo\controller\finance\Income; use huo\controller\game\Game; use huo\controller\integral\MemIa; use huo\controller\member\MemCache; use huo\controller\member\MemWallet; use huo\controller\request\Request; use huo\controller\wallet\WalletRequest; use huo\model\game\GameextModel; use huo\model\log\OrderCpLogModel; use huo\model\member\MemGameModel; use huo\model\member\MemoauthModel; use huolib\constant\AgentConst; use huolib\constant\CommonConst; use huolib\constant\IaConst; use huolib\constant\OrderConst; use huolib\constant\WalletConst; use huolib\pay\Pay; use huolib\status\CommonStatus; use huolib\status\IntegralStatus; use huolib\status\OrderStatus; use huolib\status\SettleStatus; use huolib\tool\StrUtils; use huolib\tool\Time; use huomp\controller\game\GameMini; use huomp\model\weixin\OaMchModel; use huoMpAd\MpReportData; use think\Config; use think\Exception; use think\Log; class Notify extends Base { protected function retSucMsg($code, $data = []) { $_msg = OrderStatus::getMsg($code); return $this->huoSuccess($code, $_msg, $data); } protected function retErrMsg($code) { $_err_msg = OrderStatus::getMsg($code); return $this->huoError($code, $_err_msg); } /** * CP通知 * * @param string $order_id * * @return array|mixed */ public function notify($order_id = '') { if (empty($order_id)) { return $this->retErrMsg(OrderStatus::ORDER_ID_EMPTY); } $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id); if (false == $_order_data) { return $this->retErrMsg(OrderStatus::ORDER_NOT_EXISTS); } if (OrderConst::PAY_STATUS_SUC != $_order_data['status']) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&code=".OrderStatus::ORDER_NOT_PAY.'&order_data.' .json_encode($_order_data), LOG::LOG ); return $this->retErrMsg(OrderStatus::ORDER_NOT_PAY); } if (OrderConst::CP_STATUS_SUC == $_order_data['cp_status']) { return $this->retSucMsg(OrderStatus::NO_ERROR); } $_param = $this->setCpParam($_order_data); $_cp_url = (new Game())->getCpPaybackUrl($_order_data['app_id']); if (empty($_cp_url)) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&code=".OrderStatus::NOTIFY_URL_EMPTY.'&order_data.' .json_encode($_order_data), LOG::ERROR ); return $this->retErrMsg(OrderStatus::NOTIFY_URL_EMPTY); } $_nc_data = $this->notifyCp($_cp_url, $_param); if (empty($_nc_data)) { return $this->retErrMsg(OrderStatus::UNKNOWN_ERROR); } /* 更新订单信息 */ $_order_data['cp_status'] = $_nc_data[1]; $_order_data['notify_cnt'] += $_nc_data[0]; $_order_data['last_notify_time'] = time(); if (OrderConst::CP_STATUS_SUC == $_nc_data[1]) { $_order_data['finish_time'] = time(); $_rs = SdkOrderCache::ins()->updateOrder($_order_data['order_id'], $_order_data); if (true == $_rs) { $this->updateAfterNotify($_order_data); $_code = OrderStatus::NO_ERROR; } else { $_code = OrderStatus::INNER_ERROR; } } else { // 兼容前端接口查单和支付通知同时修改cp通知状态导致重复问题 $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id); if (OrderConst::CP_STATUS_SUC == $_order_data['cp_status']) { $_code = OrderStatus::NO_ERROR; return $this->retSucMsg($_code); } $_order_data['is_handle'] = OrderConst::ORDER_IS_HANDLE; SdkOrderCache::ins()->updateOrder($_order_data['order_id'], $_order_data); $_code = OrderStatus::NOTIFY_FAIL; $_class_name = '\\huoOrderRepeat\\controller\\OrderRepeat'; if (Config::get('ORDER_REPEAT_QUEUE') && class_exists($_class_name)) { (new $_class_name())->cpNotifyQueue($_order_data['order_id']); } } /* 插入通知Log */ $_data['pay_id'] = get_val($_order_data, 'id', 0); $_data['order_id'] = get_val($_order_data, 'order_id', ''); $_data['cp_order_id'] = get_val($_order_data, 'cp_order_id', 0); $_data['status'] = get_val($_order_data, 'status', ''); $_data['cp_status'] = get_val($_order_data, 'cp_status', 0); $_data['cp_payback_url'] = $_cp_url; $_data['params'] = $_param; $_data['ext'] = get_val($_order_data, 'ext', ''); $_data['notify_cnt'] = get_val($_order_data, 'notify_cnt', ''); $_oc_model = new OrderCpLogModel(); $_oc_model->insertLog($_data); return $this->retSucMsg($_code); } /** * @param $_order_data */ public function updateAfterNotify($_order_data) { // TODO: wuyonghong 2018/4/28 通知后更新 } /** * @param $cp_url * @param $param * * @return array */ public function notifyCp($cp_url, $param) { $_i = 0; $_cp_status = 1; while (1) { $_i++; $_cp_rs = Request::cpPayback($cp_url, $param); if ($_cp_rs > 0) { $_cp_status = 2; break; } else { $_cp_status = 3; sleep(1); } if ($_i == 3) { break; } } return [$_i, $_cp_status]; } /** * 设置通知CP参数 * * @param array $order_data * * @return bool|string */ public function setCpParam($order_data = []) { $_cp_rq_data['app_id'] = get_val($order_data, 'app_id'); $_cp_rq_data['cp_order_id'] = get_val($order_data, 'cp_order_id'); $_cp_rq_data['mem_id'] = get_val($order_data, 'mg_mem_id', 0);/* 使用游戏玩家ID */ $_cp_rq_data['order_id'] = get_val($order_data, 'order_id'); $_cp_rq_data['order_status'] = get_val($order_data, 'status'); $_cp_rq_data['pay_time'] = get_val($order_data, 'create_time'); $_cp_rq_data['product_id'] = get_val($order_data, 'product_id'); $_cp_rq_data['product_name'] = get_val($order_data, 'product_name'); $_cp_rq_data['product_price'] = get_val($order_data, 'amount'); $_cp_rq_data['ext'] = get_val($order_data, 'ext'); $_param = StrUtils::argSort($_cp_rq_data); $_signstr = StrUtils::createLinkString($_param); /* 获取游戏信息 */ $_app_key = (new Game())->getAppKey($_cp_rq_data['app_id']); if (empty($_app_key)) { return false; } $_sign = md5($_signstr."&app_key=".$_app_key); $_cp_rq_data['sign'] = $_sign; return $_signstr."&sign=".$_sign; } /** * 支付回调处理 * * @param $product_id * @param $order_id * @param $trade_no * @param $amount * @param $payway */ public function payNotify($product_id, $order_id, $trade_no, $amount, $payway) { $_notify_data['product_id'] = $product_id; $_notify_data['order_id'] = $order_id; $_notify_data['trade_no'] = $trade_no; $_notify_data['amount'] = $amount; $_notify_data['payway'] = $payway; $_soc_class = SdkOrderCache::ins(); if (empty($order_id)) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&step1&code=".OrderStatus::ORDER_ID_EMPTY.'¬ify_data.' .http_build_query($_notify_data), LOG::ERROR ); return false; } if (empty($amount)) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&step2&code=".OrderStatus::ORDER_AMOUNT_IS_ZERO .'¬ify_data.' .http_build_query($_notify_data), LOG::ERROR ); return false; } $_order_data = $_soc_class->getInfoByOrderId($order_id); if (false == $_order_data) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&step3&code=".OrderStatus::ORDER_NOT_EXISTS.'¬ify_data.' .http_build_query($_notify_data), LOG::ERROR ); return false; } $_amount = number_format($amount, 2, '.', ''); $_order_amount = number_format($_order_data['real_amount'], 2, '.', ''); if (($_amount < $_order_amount)) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&step4&code=".OrderStatus::NOTIFY_AMOUNT_ERROR.'¬ify_data.' .http_build_query($_notify_data).'&order_data='.http_build_query($_order_data), LOG::ERROR ); return false; } if (OrderConst::PAY_STATUS_SUC == $_order_data['status']) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&step5&code=".OrderStatus::ORDER_HAS_PAY.'¬ify_data.' .http_build_query($_notify_data).'&order_data='.http_build_query($_order_data), LOG::LOG ); return false; } /* 更新订单支付状态 */ $_order_data['status'] = OrderConst::PAY_STATUS_SUC; $_order_data['payway'] = $payway; $_order_data['remark'] = $trade_no; $_order_data['pay_time'] = time(); $_rs = $_soc_class->updateOrder($_order_data['order_id'], $_order_data); if (false == $_rs) { return false; } /* Modified by wuyonghong BEGIN 2018/3/26 ISSUES:5314 LTV */ /* 充值时计算LTV */ $_ltv_class = new \ltv\Ltv(); $_mem_data = (new \huo\model\member\MemberModel())->getInfoById( $_order_data['mem_id'] ); $_ltv_class->charge( $_mem_data['app_id'], $_mem_data['agent_id'], $_order_data['app_id'], $_order_data['amount'], $_order_data['update_time'], $_mem_data['create_time'] ); /* END 2018/3/26 ISSUES:5314 */ /* 通知CP */ $this->doAfterPayNotify($order_id); // 买量数据回传 try { (new MpReportData())->payReport($order_id); } catch (\Exception $exception) { \think\Log::write(['pppppp', $exception->getTraceAsString(), 'error', true]); } return true; } /** * 支付成功后 需要做的操作 * * @param $order_id * * @return array */ public function doAfterPayNotify($order_id) { /* 更新游戏信息 */ $this->upGameAfterPay($order_id); /* 更新玩家信息 */ $_rs = $this->upMemAfterPay($order_id); if (CommonStatus::NO_ERROR != $_rs['code']) { return $this->huoReturn($_rs); } /* 计算渠道收益 */ $this->upAgentAfterPay($order_id); /* 异步处理数据 */ (new \huo\controller\queue\Order())->fromSdkOrder($order_id); /* 通知CP */ $_rdata = $this->notify($order_id); return $this->huoReturn($_rdata); } /** * 更新渠道数据 * * @param $order_id */ public function upAgentAfterPay($order_id) { /* 计算渠道收益 */ (new Income())->incomeFromSdkOrder($order_id); } /** * 更新玩家数据 * * @param $order_id */ public function upMemAfterPay($order_id) { $_soc_class = SdkOrderCache::ins(); $_order_data = $_soc_class->getInfoByOrderId($order_id); /* 扣除平台币 平台币扣除不成功返回 */ if (StrUtils::compareNumber($_order_data['ptb_amount'], CommonConst::CONST_ZERO_COMPARE) > 0) { $_wr_class = new WalletRequest(); $_wr_class->setDataFromSdkOrder($_order_data); $_order_data['status'] = OrderConst::PAY_STATUS_SUC; $_wr_class->setStatus($_order_data['status']); $_rs = (new MemWallet())->createPoOrder($_wr_class); if (SettleStatus::NO_ERROR != $_rs) { /* 记录所有Log */ return $this->huoError($_rs, SettleStatus::getMsg($_rs)); } else { $_order_data['pay_time'] = time(); $_soc_class->updateOrder($order_id, $_order_data); } } /* 扣除游戏币 游戏币扣除不成功返回 */ if (StrUtils::compareNumber($_order_data['gm_amount'], CommonConst::CONST_ZERO_COMPARE) > 0) { $_wr_class = new WalletRequest(); $_wr_class->setDataFromSdkOrder($_order_data); $_order_data['status'] = OrderConst::PAY_STATUS_SUC; $_wr_class->setStatus($_order_data['status']); $_rs = (new MemWallet())->createGmoOrder($_wr_class); if (SettleStatus::NO_ERROR != $_rs) { /* 记录所有Log */ return $this->huoError($_rs, SettleStatus::getMsg($_rs)); } else { $_order_data['pay_time'] = time(); $_soc_class->updateOrder($order_id, $_order_data); } } /* 充值成功获取积分 */ $_mem_id = $_order_data['mem_id']; if (!empty($_mem_id)) { $_rs = (new MemIa($_mem_id))->doItgAct(IaConst::IA_DAY_FIRST_CHARGE, $order_id); if (CommonStatus::NO_ERROR != $_rs['code']) { if (IntegralStatus::ITG_IA_ERROR != $_rs['code']) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&returndata=".json_encode($_rs).'&order_data=' .http_build_query($_order_data), LOG::LOG ); } else { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&returndata=".json_encode($_rs).'&order_data=' .http_build_query($_order_data), LOG::ERROR ); } } } /* 更新玩家信息 */ $_mc_class = MemCache::ins(); $_me_data = $_mc_class->getMeInfoById($_mem_id); $_me_data['last_money'] = $_order_data['amount']; $_me_data['sum_money'] += $_order_data['amount']; // 玩家游戏充值 $_mem_game_model = new MemGameModel(); $_mem_game_model->where(['id' => $_order_data['mg_mem_id']]) ->setInc('sum_money', $_order_data['amount']); list($_today_start, $_today_end) = Time::today(); if ($_today_start > $_me_data['last_pay_time']) { /* 非本日充值 */ $_me_data['day_money'] = $_order_data['amount']; } else { $_me_data['day_money'] += $_order_data['amount']; } list($_week_start, $_week_end) = Time::week(); if ($_week_start > $_me_data['last_pay_time']) { /* 非本周充值 */ $_me_data['week_money'] = $_order_data['amount']; } else { $_me_data['week_money'] += $_order_data['amount']; } list($_month_start, $_month_end) = Time::month(); if ($_month_start > $_me_data['last_pay_time']) { /* 非本月充值 */ $_me_data['month_money'] = $_order_data['amount']; } else { $_me_data['month_money'] += $_order_data['amount']; } $_me_data['order_suc_cnt'] += 1; $_me_data['last_pay_time'] = $_order_data['pay_time']; $_mc_class->updateMeCache($_mem_id, $_me_data); /* Modified by chenbingling BEGIN 2019/12/2 ISSUES:10837 实名认证统计 */ (new \huoIdentify\controller\Pay())->updateMoney($_order_data['mem_id'], $_order_data['amount']); /* END 2019/12/2 ISSUES:10837 */ $_code = CommonStatus::NO_ERROR; return $this->huoError($_code, SettleStatus::getMsg($_code)); } /** * @param string $payway * * @param string $product_id * * @param int $app_id 应用ID * @param string $order_id 订单id * * @return bool */ public function notifyUrl($payway, $product_id = '', $app_id = 0, $order_id = '') { try { $_pay_class = Pay::ins()->get($payway); } catch (Exception $e) { Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&payway=".$payway.'&data='.json_encode($_REQUEST), LOG::ERROR ); exit('fail'); } $_config = []; switch ($product_id) { case WalletConst::WALLET_PRODUCT_MEM_PTB: case WalletConst::WALLET_PRODUCT_MEM_GM: case WalletConst::WALLET_PRODUCT_AGENT_PTB: case WalletConst::WALLET_PRODUCT_ACCOUNT: { $_order_class = '\\huo\\controller\\wallet\\Notify'; $_func = 'payNotify'; } break; case WalletConst::WALLET_PRODUCT_MP: $_order_class = '\\huo\\controller\\pay\\Notify'; $_func = 'payNotify'; $_pay_class->setOrderClass($_order_class); $_pay_class->setFunc($_func); $_config = (new GameMini())->getPayConfByMpAppId($app_id); return $_pay_class->notifyUrl($_config); case WalletConst::WALLET_PRODUCT_WXKF: $_order_class = '\\huo\\controller\\pay\\Notify'; $_func = 'payNotify'; $_pay_class->setOrderClass($_order_class); $_pay_class->setFunc($_func); $_config = $_config = (new OaMchModel())->getPayConfByOaId($app_id);; return $_pay_class->notifyUrl($_config); default: { $_order_class = '\\huo\\controller\\pay\\Notify'; $_func = 'payNotify'; $_order_info = SdkOrderCache::ins()->getInfoByOrderId($order_id); $_app_id = get_val($_order_info, 'app_id', CommonConst::CONST_ZERO); $_config = (new PaywayConf())->getConfByAppPayway($_app_id, $payway); } } $_pay_class->setOrderClass($_order_class); $_pay_class->setFunc($_func); return $_pay_class->notifyUrl($_config); } /** * 更新游戏信息 * * @param $order_id * * @return : * @author : chengshibin * @date : 2019/2/18 18:33 * @since : HUOSDK 8.0 * @modified: 2019/2/18 18:33 */ public function upGameAfterPay($order_id) { $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id); $_app_id = $_order_data['app_id']; /* 充值成功获取积分 */ $_mem_id = $_order_data['mem_id']; /* 更新玩家信息 */ $_mc_class = MemCache::ins(); $_mem_data = $_mc_class->getInfoById($_mem_id); $_me_data = $_mc_class->getMeInfoById($_mem_id); /* 更新游戏扩展信息 */ $_game_ext_class = new GameextModel(); $_game_ext_data = $_game_ext_class->getDetail($_app_id); $_game_ext_data['sum_money'] += $_order_data['amount']; $_game_ext_data['sum_real_money'] += $_order_data['real_amount']; /*首充总额*/ if (0 == $_me_data['last_pay_time']) { $_game_ext_data['first_pay_money'] += $_order_data['amount']; /*首付当日总额*/ if (date('Y-m-d') == date('Y-m-d', $_mem_data['create_time'])) { $_game_ext_data['first_pay_sum_money'] += $_order_data['amount']; $_game_ext_data['reg_sum_money'] += $_order_data['amount']; } } $_game_ext_class->updateData($_game_ext_data, $_app_id); $_code = CommonStatus::NO_ERROR; return $this->huoError($_code, SettleStatus::getMsg($_code)); } }