* @version : HUOSDK 7.0 */ namespace huoMpay; use huo\controller\common\Base; use huo\controller\common\HuoSession; use huo\controller\pay\Notify; use huo\controller\pay\Sdk; use huo\controller\pay\SdkOrderCache; use huolib\constant\OrderConst; use huolib\constant\PaywayConst; use huolib\status\OrderStatus; use huolib\tool\StrUtils; use huomp\controller\game\GameMini; use huomp\model\wallet\MgmLogModel; use huomp\model\wallet\MidasGmMemModel; use think\Log; class Payments extends Base { const MGM_QUERY = 1; /* 1 查询 */ const MGM_PAY = 2; /* 2 扣费 */ const MGM_PRESENT = 3; /* 3 赠送 */ const MGM_CANCEL = 4; /* 4 取消支付 */ /** * 获取余额并且支付 * * @param int $mem_id 玩家ID * @param string $order_id 订单ID * * @return array */ public function getBalanceAndPay($mem_id, $order_id) { if (empty($order_id)) { $_code = OrderStatus::ORDER_ID_EMPTY; return $this->huoError($_code, OrderStatus::getMsg($_code)); } $_soc_class = SdkOrderCache::ins(); $_order_data = $_soc_class->getInfoByOrderId($order_id); if (empty($_order_data)) { $_code = OrderStatus::ORDER_ID_ERROR; return $this->huoError($_code, OrderStatus::getMsg($_code)); } if ($mem_id != $_order_data['mem_id']) { $_code = OrderStatus::ORDER_NOT_EXISTS; return $this->huoError($_code, OrderStatus::getMsg($_code)); } $mem_id = $_order_data['mem_id']; $_rdata['status'] = $_order_data['status']; $_rdata['cp_status'] = $_order_data['cp_status']; if (OrderConst::CP_STATUS_SUC != $_order_data['cp_status'] && OrderConst::PAY_STATUS_SUC == $_order_data['status']) { $_rs = (new Notify())->notify($order_id); if (OrderStatus::NO_ERROR == $_rs['code']) { $_rdata['status'] = OrderConst::PAY_STATUS_SUC; $_rdata['cp_status'] = OrderConst::CP_STATUS_SUC; } $_code = OrderStatus::NO_ERROR; return $this->huoSuccess($_code, OrderStatus::getMsg($_code), $_rdata); } /* 获取余额 */ $_rs = $this->midasGetBalance($mem_id, $order_id); if (OrderStatus::NO_ERROR != $_rs['code']) { return $this->huoError($_rs['code'], $_rs['msg']); } $_data = $_rs['data']; $_mgm_model = (new MidasGmMemModel()); $_mgm_data = $_mgm_model->getDataOrInsert($mem_id, $_order_data['app_id']); $_diff_gm_cnt = StrUtils::formatNumber($_data['save_amt'] - $_mgm_data['m_save_amt']); /* 数量大于等于充值金额 */ $_product_cnt = StrUtils::formatNumber($_order_data['product_cnt']); /* 变化的游戏币必须币充值的游戏币多 */ if ($_diff_gm_cnt < $_product_cnt) { $_code = OrderStatus::NOTIFY_AMOUNT_ERROR; Log::write( "func=".__FUNCTION__."&class=".__CLASS__."&step1&code=".$_code.'&data.' .http_build_query($_data).'&order_data='.http_build_query($_order_data).'&mgm_data='.http_build_query( $_mgm_data ).'&diff_gm_cnt='.$_diff_gm_cnt.'&product_cnt='.$_product_cnt.'&rs='.json_encode($_rs), LOG::ERROR ); return $this->huoError($_code, OrderStatus::getMsg($_code)); } /* 扣除所有游戏币 */ /* 获取余额 */ $_rs = $this->midasPay($mem_id, $order_id); if (OrderStatus::NO_ERROR != $_rs['code'] && 90012 != $_rs['code']) { return $this->huoError($_rs['code'], $_rs['msg']); } $_rs = (new Notify())->payNotify( $_order_data['product_id'], $order_id, '', $_order_data['amount'], $_order_data['payway'] ); if (false == $_rs) { $_code = OrderStatus::INNER_ERROR; return $this->huoError($_code, OrderStatus::getMsg($_code)); } /* 更新米大师游戏币 */ $_mgm_data['m_balance'] = $_data['balance'] - $_product_cnt; $_mgm_data['m_gen_balance'] = $_data['gen_balance']; $_mgm_data['m_save_amt'] += $_product_cnt; $_mgm_data['m_save_sum'] = $_data['save_sum']; $_mgm_data['m_cost_sum'] = $_data['cost_sum']; $_mgm_data['m_present_sum'] = $_data['present_sum']; $_mgm_data['sum_money'] += $_order_data['amount']; $_mgm_data['total'] += $_product_cnt; $_mgm_data['remain'] += $_mgm_data['m_balance']; $_mgm_model->updateData($_mgm_data, $_mgm_data['id']); /* 插入每条记录 */ // TODO: wuyonghong 2018/8/16 插入log记录 /* 从订单中获取状态 */ $_statues = (new Sdk())->getStatus($order_id); if (false == $_statues) { $_code = OrderStatus::ORDER_ID_ERROR; return $this->huoError($_code, OrderStatus::getMsg($_code), $_rdata); } $_code = OrderStatus::NO_ERROR; $_rdata = [ 'order_id' => $order_id, 'status' => $_statues['status'], 'cp_status' => $_statues['cp_status'] ]; return $this->huoSuccess($_code, OrderStatus::getMsg($_code), $_rdata); } /** * @param string $app_id 应用ID * @param bool $is_sand 是否沙盒环境 * * @return array */ public function getBaseParam($app_id, $is_sand = false) { $_mpay_data = (new GameMini())->getMpayConf($app_id, $is_sand); $_rdata['appid'] = $_mpay_data['appid']; /* 小程序ID */ $_rdata['offer_id'] = $_mpay_data['offer_id']; /* 米大师支付应用ID */ $_rdata['ts'] = time(); $_rdata['zone_id'] = '1'; $_rdata['pf'] = 'android'; $_rdata['app_secret'] = $_mpay_data['app_secret']; /* 小程序AppSecret */ $_rdata['app_key'] = $_mpay_data['app_key']; /* 米大师AppKey */ return $_rdata; } /** * @param int $mem_id * @param int $app_id * * @return string */ public function getOpenId($mem_id, $app_id = 0) { $_open_id = (new HuoSession($mem_id, $app_id))->getOpenId(); if (!empty($_open_id)) { return $_open_id; } return ''; } /** * @param int $mem_id * @param int $app_id * * @return string */ public function getSessionKey($mem_id, $app_id) { $_session_key = (new HuoSession($mem_id, $app_id))->getAccessToken(); if (!empty($_session_key)) { return $_session_key; } return ''; } /** * 开通了虚拟支付的小游戏,可以通过本接口查看某个用户的游戏币余额 * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasGetBalance.html * * @param int $mem_id 玩家ID * @param string $order_id 订单ID * * @return int|mixed */ public function midasGetBalance($mem_id, $order_id = '') { $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id); $_is_sand = true; if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) { $_is_sand = false; } $_app_id = $_order_data['app_id']; $_uri = '/cgi-bin/midas/getbalance'; if ($_is_sand) { $_uri = '/cgi-bin/midas/sandbox/getbalance'; } $_base_params = $this->getBaseParam($_app_id, $_is_sand); $_open_id = $this->getOpenId($mem_id, $_app_id); $_session_key = $this->getSessionKey($mem_id, $_app_id); $_params = [ 'openid' => $_open_id, 'appid' => $_base_params['appid'], 'offer_id' => $_base_params['offer_id'], 'ts' => $_base_params['ts'], 'zone_id' => $_base_params['zone_id'], 'pf' => $_base_params['pf'], //'user_ip' => $_order_data['payext']['ip'],/* 用户外网 IP */ ]; $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */ $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */ $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key); if (OrderStatus::NO_ERROR == $_rs['code']) { $_mgm_log_data['mem_id'] = $mem_id; $_mgm_log_data['app_id'] = $_order_data['app_id']; $_mgm_log_data['order_id'] = $_order_data['order_id']; $_mgm_log_data['m_balance'] = $_rs['data']['balance']; $_mgm_log_data['m_gen_balance'] = $_rs['data']['gen_balance']; $_mgm_log_data['m_save_amt'] = $_rs['data']['save_amt']; $_mgm_log_data['m_save_sum'] = $_rs['data']['save_sum']; $_mgm_log_data['m_cost_sum'] = $_rs['data']['cost_sum']; $_mgm_log_data['m_present_sum'] = $_rs['data']['present_sum']; $_mgm_log_data['server_id'] = $_base_params['zone_id']; $_mgm_log_data['type'] = self::MGM_QUERY; (new MgmLogModel())->insertLog($_mgm_log_data); } return $_rs; } /** * 开通了虚拟支付的小游戏,若扣除游戏币的订单号在有效时间内,可以通过本接口取消该笔扣除游戏币的订单 * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasCancelPay.html * * * @param int $mem_id 玩家ID * @param string $order_id 订单ID * * @return array|mixed */ function midasCancelPay($mem_id, $order_id) { $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id); $_is_sand = true; if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) { $_is_sand = false; } $_app_id = $_order_data['app_id']; $_uri = '/cgi-bin/midas/cancelpay'; if ($_is_sand) { $_uri = '/cgi-bin/midas/sandbox/cancelpay'; } $_base_params = $this->getBaseParam($_app_id, $_is_sand); $_open_id = $this->getOpenId($mem_id); $_session_key = $this->getSessionKey($mem_id); $_params = [ 'openid' => $_open_id, 'appid' => $_base_params['appid'], 'offer_id' => $_base_params['offer_id'], 'ts' => $_base_params['ts'], 'zone_id' => $_base_params['zone_id'], 'pf' => $_base_params['pf'], //'user_ip' => $_order_data['payext']['ip'],/* 用户外网 IP */ 'bill_no' => $_order_data['order_id'], // 'pay_item' => $_order_data['payext']['product_name'], /* 道具名称 */ ]; $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */ $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */ $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key); if (OrderStatus::NO_ERROR == $_rs['code']) { $_mgm_log_data['mem_id'] = $mem_id; $_mgm_log_data['app_id'] = $_order_data['app_id']; $_mgm_log_data['order_id'] = $_order_data['order_id']; $_mgm_log_data['type'] = self::MGM_CANCEL; (new MgmLogModel())->insertLog($_mgm_log_data); } return $_rs; } /** * 米大师付款 * 开通了虚拟支付的小游戏,可以通过本接口扣除某个用户的游戏币。 * 由于可能存在接口调用超时或返回系统失败,但是游戏币实际已经扣除的情况,所以当该接口返回系统失败时,可以用相同的bill_no再次调用本接口,直到返回非系统失败为止,不会重复扣款,也可以调用取消支付接口取消本次扣款。 * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasPay.html * * * @param int $mem_id 玩家ID * @param string $order_id 订单ID * * @return array|mixed */ function midasPay($mem_id, $order_id) { $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id); $_is_sand = true; if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) { $_is_sand = false; } $_app_id = $_order_data['app_id']; $_uri = '/cgi-bin/midas/pay'; if ($_is_sand) { $_uri = '/cgi-bin/midas/sandbox/pay'; } $_base_params = $this->getBaseParam($_app_id, $_is_sand); $_open_id = $this->getOpenId($mem_id, $_app_id); $_session_key = $this->getSessionKey($mem_id, $_app_id); $_params = [ 'openid' => $_open_id, 'appid' => $_base_params['appid'], 'offer_id' => $_base_params['offer_id'], 'ts' => $_base_params['ts'], 'zone_id' => $_base_params['zone_id'], 'pf' => $_base_params['pf'], // 'user_ip' => $_order_data['payext']['ip'], // 'pay_item' => $_order_data['payext']['product_name'], // 'app_remark' => $_order_data['payext']['remark'], 'amt' => $_order_data['product_cnt'], /* 扣除游戏币数量,不能为 0 */ 'bill_no' => $_order_data['order_id'], ]; $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */ $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */ $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key); if (OrderStatus::NO_ERROR == $_rs['code']) { $_mgm_log_data['mem_id'] = $mem_id; $_mgm_log_data['app_id'] = $_order_data['app_id']; $_mgm_log_data['order_id'] = $_rs['data']['bill_no']; $_mgm_log_data['m_balance'] = $_rs['data']['balance']; $_mgm_log_data['m_used_gen_balance'] = isset($_rs['data']['used_gen_amt']) ? $_rs['data']['used_gen_amt'] : 0; $_mgm_log_data['type'] = self::MGM_PAY; (new MgmLogModel())->insertLog($_mgm_log_data); } return $_rs; } /** * 米大师赠送 * 开通了虚拟支付的小游戏,可以通过该接口赠送游戏币给某个用户。 * https://developers.weixin.qq.com/minigame/dev/document/midas-payment/midasPresent.html * * * @param int $mem_id 玩家ID * @param string $order_id 订单ID * @param int $present_counts 赠送游戏币的个数,不能为0 * * * 0 请求成功 * -1 系统繁忙,此时请开发者稍候再试 * 90009 mp_sig签名错误 * 90010 用户未登录或登录态已过期 * 90011 sig签名错误 * 90012 订单已存在 * 90017 没有调用接口的权限 * 90018 参数错误 * * @return array|mixed */ function midasPresent($mem_id, $order_id, $present_counts) { $_order_data = SdkOrderCache::ins()->getInfoByOrderId($order_id); $_is_sand = true; if (PaywayConst::PAYWAY_MPAY == $_order_data['payway']) { $_is_sand = false; } $_app_id = $_order_data['app_id']; $_uri = '/cgi-bin/midas/present'; if ($_is_sand) { $_uri = '/cgi-bin/midas/sandbox/present'; } $_base_params = $this->getBaseParam($_app_id, $_is_sand); $_open_id = $this->getOpenId($mem_id); $_session_key = $this->getSessionKey($mem_id); $_params = [ 'openid' => $_open_id, 'appid' => $_base_params['appid'], 'offer_id' => $_base_params['offer_id'], 'ts' => $_base_params['ts'], 'zone_id' => $_base_params['zone_id'], 'pf' => $_base_params['pf'], // 'user_ip' => $_order_data['payext']['ip'], 'bill_no' => $_order_data['order_id'], 'present_counts' => $present_counts, /* 赠送游戏币的个数,不能为0 */ ]; $_mp_app_secret = $_base_params['app_secret']; /* 小程序AppSecret */ $_midas_app_key = $_base_params['app_key']; /* 米大师密钥 */ $_rs = MpaySign::apiPay($_uri, $_params, $_mp_app_secret, $_midas_app_key, $_session_key); if (OrderStatus::NO_ERROR == $_rs['code']) { $_mgm_log_data['mem_id'] = $mem_id; $_mgm_log_data['app_id'] = $_order_data['app_id']; $_mgm_log_data['order_id'] = $_rs['data']['bill_no']; $_mgm_log_data['m_balance'] = $_rs['data']['balance']; $_mgm_log_data['type'] = self::MGM_PRESENT; (new MgmLogModel())->insertLog($_mgm_log_data); } return $_rs; } }