GamePayService.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. <?php
  2. namespace app\service;
  3. use app\common\logic\PayHandle;
  4. use app\common\model\ChannelFrozen;
  5. use app\common\model\Cpurl;
  6. use app\common\model\Members;
  7. use app\common\model\Game;
  8. use app\common\model\Pay as PayModel;
  9. use app\common\model\PayCpinfo;
  10. use app\common\model\MemberChannelGame;
  11. use app\common\logic\Pay as PayLogic;
  12. use app\common\model\Subaccount;
  13. use think\Config;
  14. use think\Db;
  15. use think\Exception;
  16. use app\common\model\App;
  17. use think\Model;
  18. use think\Request;
  19. class GamePayService
  20. {
  21. protected $payRequestLimit = 5; //重复下单的限制时间
  22. /**
  23. * 游戏支付
  24. * @param $data
  25. */
  26. public function gamePay($data, $urlType = 1)
  27. {
  28. $paytype = $data['paytype'];// 支付方式
  29. $pay_scene = $data['paytype'];
  30. // ## 随机为新的支付渠道 ##
  31. // 取消代金卷、平台币的判断处理
  32. if(!in_array($paytype, ['coupon', 'coinpay'])){
  33. // if(!in_array($paytype, ['wx_h5', 'ali_h5']) && $data['device'] != 4){
  34. if (version_compare($data['version'], config('pay_handle_version'), '>')) {
  35. $payType = [
  36. 'wx_h5' => ['qzl_wx_h5', 'ldys_wx_h5', 'ybzf_wxmp_h5', 'yyyb_wx_h5', 'xty_wx_h5', 'qmf_wxmp_h5'],
  37. 'ali_h5' => ['old-zfb-wap', 'ldys_zfb_h5', 'xty_ali_h5', 'yyyb_ali_h5', 'qzl_ali_h5'],
  38. 'ali_app' => ['zfb'],
  39. 'ptb' => ['coinpay'],
  40. ];
  41. } else {
  42. // 老版本
  43. $payType = [
  44. 'wx_h5' => ['qzl_wx_h5', 'ldys_wx_h5', 'ybzf_wxmp_h5', 'yyyb_wx_h5', 'xty_wx_h5', 'qmf_wxmp_h5'],
  45. 'ali_h5' => ['old-zfb-wap', 'xty_ali_h5'],
  46. 'ali_app' => ['zfb'],
  47. ];
  48. }
  49. $newPayType = handlePayType($payType);
  50. // 判断所属类型
  51. if (in_array($data['paytype'], $newPayType['wx_h5'])) {
  52. $pay_scene = 'wx_h5';
  53. } else if (in_array($data['paytype'], $newPayType['ali_h5'])) {
  54. $pay_scene = 'ali_h5';
  55. } else if (in_array($data['paytype'], $newPayType['ali_app'])) {
  56. $pay_scene = 'ali_app';
  57. } else if (in_array($data['paytype'], $newPayType['ptb'])) {
  58. $pay_scene = 'ptb';
  59. } else {
  60. // 不能这样判断,因为会有ptb
  61. // return ['code' => -111, 'msg' => '支付方式有误!', 'data' => []];
  62. }
  63. // }
  64. // 去除支付中包含有混合支付标识(获取支付方式)
  65. $new_pay_scene = str_replace(['mix-', 'coin-'], '', $pay_scene);
  66. // 随机支付管控,没有则走默认配置的
  67. if ((version_compare($data['version'], config('pay_handle_version'), '>') && $new_pay_scene) || (isInArrType($newPayType, $paytype) && $new_pay_scene)) {
  68. $newPayType = (new PayHandle())->getPayChannel($new_pay_scene, $data['gameid'], $data['version']);
  69. if (empty($newPayType['data']['paytype'])) {
  70. return ['data' => '', 'code' => -110, 'msg' => "支付配置有误!当前游戏或者版本未开启支付!({$newPayType['code']})"];
  71. }
  72. $paytype = $newPayType['data']['paytype'];
  73. if (substr($data['paytype'], 0, 4) == 'mix-') {
  74. $data['paytype'] = 'mix-' . $paytype;
  75. } else if (substr($data['paytype'], 0, 5) == 'coin-') {
  76. $data['paytype'] = 'coin-' . $paytype;
  77. } else {
  78. $data['paytype'] = $newPayType['data']['paytype'];
  79. }
  80. } else {
  81. // 老版支付使用指定
  82. $setPayType = model('common/Setting')->where(['name' => 'OLD_PAY_WX_TYPE'])->value('value');
  83. if ($setPayType) {
  84. // qmf_wxmp_h5 = 标识代替其他支付方式
  85. if (strstr($data['paytype'], 'qmf_wxmp_h5') !== false) {
  86. $paytype = $setPayType;
  87. if ($data['paytype'] == 'qmf_wxmp_h5') {
  88. $data['paytype'] = $setPayType;
  89. } else if ($data['paytype'] == 'mix-qmf_wxmp_h5') {
  90. $data['paytype'] = 'mix-' . $setPayType;
  91. } else if ($data['paytype'] == 'coin-qmf_wxmp_h5') {
  92. $data['paytype'] = 'coin-' . $setPayType;
  93. }
  94. }
  95. }
  96. }
  97. }
  98. // ## 随机为新的支付渠道 - END ##
  99. $time = NOW_TIMESTAMP;
  100. $data['orderid'] = $orderid = makeOrderid();
  101. $pay_status = 0; //cy_pay表的支付状态
  102. $cp_payflag = 0; //cy_paycpinfo表的支付状态
  103. $memberModel = new Members();
  104. $frozenModel = new ChannelFrozen();
  105. $cpurlModel = new Cpurl();
  106. $gameModel = new Game;
  107. $payModel = new PayModel;
  108. $payCpinfoModel = new PayCpinfo;
  109. $memberChannelGameModel = new MemberChannelGame;
  110. $payLogic = new PayLogic();
  111. //当前游戏的包是否禁止消费(非归属渠道)
  112. if (isFrozenOption($data['channel_id'], $data['gameid'], 'consume')) {
  113. return ['data' => '', 'code' => -100, 'msg' => '您所在渠道已经被禁止在此游戏消费'];
  114. }
  115. if (empty($data['ptb_amt']) && (substr($data['paytype'], 0, 4) == 'mix-' || $data['paytype'] == 'ptb')) {
  116. return ['code' => -100, 'msg' => '请输入专属币使用数量'];
  117. }
  118. if ((empty($data['coin_amt']) || $data['coin_amt'] <= 0) && (substr($data['paytype'], 0, 5) == 'coin-' || $data['paytype'] == 'coinpay')) {
  119. return ['code' => -100, 'msg' => '请输入平台币使用数量'];
  120. }
  121. if (empty($data['coupon_member_id']) && $data['paytype'] == 'coupon') {
  122. return ['code' => -100, 'msg' => '请选择代金券'];
  123. }
  124. $memberInfo = $memberModel->field('id,username,amount')->where(['id' => $data['member_id']])->find();
  125. if (empty($memberInfo)) {
  126. return ['code' => -100, 'msg' => '用户不存在'];
  127. }
  128. //子账号用户名
  129. $subaccountData = (new Subaccount())->field(['sub_username', 'channel_id'])->where(['member_id' => $data['member_id'], 'game_id' => $data['gameid']])->find();
  130. $data['sub_username'] = $subaccountData['sub_username']??'';
  131. if (!$data['sub_username']) {
  132. return ['data' => '', 'code' => -110, 'msg' => '账号异常'];
  133. }
  134. // 玩家在这款游戏的归属渠道
  135. $data['channel_id'] = $subaccountData['channel_id']??'';
  136. // $channel_id = $memberChannelGameModel->where(['member_id' => $data['member_id'], 'game_id' => $data['gameid']])->value('channel_id');
  137. if (empty($data['channel_id'])) {
  138. return ['data' => '', 'code' => -110, 'msg' => '无关联的归属渠道信息'];
  139. }
  140. // $data['channel_id'] = $channel_id;
  141. // 判断渠道包是否合法
  142. $channelInfo = model('Channel')->where(['status' => 1, 'id' => $data['channel_id']])->find();
  143. if (!$channelInfo && intval($data['channel_id']) <> config('EMPTY_CHANNEL_ID')) {
  144. return ['data' => '', 'code' => -110, 'msg' => '当前渠道已禁用'];
  145. } else if ($channelInfo['level'] <> 3) {
  146. return ['data' => '', 'code' => -110, 'msg' => '非推广员渠道,不能进行推广,请联系客服'];
  147. }
  148. // 当前游戏的渠道是否禁止消费(非归属渠道)
  149. if (isFrozenOption($data['channel_id'], $data['gameid'], 'consume')) {
  150. return ['data' => '', 'code' => -110, 'msg' => '您所在渠道已经被禁止在此游戏消费'];
  151. }
  152. $appModel = new App();
  153. if (!isset($data['appInfo'])) {
  154. $data['appInfo'] = $appModel->field('id,appkey,client_appkey,gameid')->where(['gameid' => $data['gameid']])->find()->toArray();
  155. }
  156. // 充值回调地址
  157. if ($urlType == 1) {
  158. $cpurl = $cpurlModel->where(['appid' => $data['appInfo']['id']])->value('url');
  159. } else {
  160. $cpurl = $cpurlModel->where(['appid' => $data['appInfo']['id']])->value('web_url');
  161. if (!$gameServerInfo = model('GameServer')->field('serverid,servername')->where(['game_id' => $data['gameid'], 'serverid' => $data['serverid']])->find()) {
  162. return ['data' => '', 'code' => -120, 'msg' => '游戏区服id参数错误'];
  163. }
  164. $data['servername'] = $gameServerInfo['servername'];
  165. if (!$memberGameServerInfo = model('MemberGameServer')->where(['member_id' => $data['member_id'], 'game_id' => $data['gameid'], 'serverid' => $data['serverid'], 'roleid' => $data['roleid']])->find()) {
  166. return ['data' => '', 'code' => -120, 'msg' => '游戏角色信息不存在'];
  167. }
  168. $data['rolename'] = $memberGameServerInfo['rolename'];
  169. $data['rolelevel'] = $memberGameServerInfo['rolelevel'];
  170. }
  171. if (empty($cpurl)) {
  172. return ['data' => '', 'code' => -130, 'msg' => '没有回调地址,请通知我方配置'];
  173. }
  174. // 游戏信息
  175. $gameInfo = $gameModel->field('order_recheck,is_pay')->where(['id' => $data['gameid']])->find();
  176. if (empty($gameInfo)) {
  177. return ['data' => '', 'code' => -130, 'msg' => '游戏id参数错误'];
  178. }
  179. if ($gameInfo['is_pay'] != 1) {
  180. return ['data' => '', 'code' => -130, 'msg' => '游戏已停止充值'];
  181. }
  182. if ($data['amount'] > 100000) {
  183. return ['data' => '', 'code' => -130, 'msg' => '您的充值金额过大,请确认是否为合法充值'];
  184. }
  185. $data['discount'] = $discount = getDiscount($data['member_id'], $data['gameid'], $data['channel_id']); // 折扣比例
  186. if ($data['ptb_amt'] > 0 && $data['coin_amt'] > 0) {
  187. return ['data' => '', 'code' => -130, 'msg' => '平台币和专属币不能同时使用'];
  188. }
  189. $data['coupon_amount'] = 0;
  190. $amount = $data['amount'];
  191. // ## 代金券使用
  192. if ($data['coupon_member_id'] > 0) {
  193. $list = model('common/CouponMember')->getPayCoupon($data['member_id'], $data['gameid'], $data['amount'], $data['coupon_member_id']);
  194. if (count($list) != 1) {
  195. return ['data' => '', 'code' => -140, 'msg' => '代金券不存在'];
  196. }
  197. if ($list[0]['is_pay'] != 1) {
  198. return ['data' => '', 'code' => -141, 'msg' => '代金券不可使用'];
  199. }
  200. if ($list[0]['money'] > $data['amount']) {
  201. if ($data['paytype'] != 'coupon') {
  202. return ['data' => '', 'code' => -142, 'msg' => '支付类型错误'];
  203. }
  204. $data['coupon_amount'] = $data['amount'];
  205. $amount = 0;
  206. } else {
  207. $data['coupon_amount'] = $list[0]['money'];
  208. // $amount = priceFormat($data['amount'] - $data['coupon_amount']);
  209. $amount = bcsub((string)$data['amount'], (string)$data['coupon_amount'], 2);
  210. }
  211. // 如果只有代金卷支付,则判断代金卷是否够支付,不够则不能下单
  212. if($data['paytype'] == 'coupon'){
  213. if($amount > 0){
  214. return ['data' => '', 'code' => -143, 'msg' => '下单失败,代金卷不能满减支付!'];
  215. }
  216. }
  217. }
  218. // dump($amount);
  219. // ## 有使用专属币时
  220. if (!empty($data['ptb_amt'])) {
  221. if ($data['ptb_amt'] > $amount) {
  222. return ['data' => '', 'code' => 0, 'msg' => '游戏专属币支付金额选择异常,平台币使用金额大于总金额'];
  223. }
  224. $userCoinInfo = model('MemberZscoin')->field('id,userid,username,game_id,amount,status')->where(['userid' => $data['member_id'], 'game_id' => $data['gameid']])->find();
  225. if (empty($userCoinInfo)) {
  226. return ['data' => '', 'code' => -150, 'msg' => '您的游戏专属币余额不足'];
  227. } else if (!$userCoinInfo['status']) {
  228. return ['data' => '', 'code' => -151, 'msg' => '您的游戏专属币账户已被冻结,不能使用'];
  229. } else if ($userCoinInfo['amount'] < $data['ptb_amt']) {
  230. return ['data' => '', 'code' => -152, 'msg' => '您的游戏专属币余额不足'];
  231. }
  232. $arrPayAmount = $payLogic->calPayAmount($amount, $data['ptb_amt'], $discount);
  233. }
  234. // 有使用平台币时
  235. else if (!empty($data['coin_amt'])) {
  236. if ($data['coin_amt'] > $amount) {
  237. return ['data' => '', 'code' => -153, 'msg' => '游戏平台币支付金额选择异常,平台币使用金额大于总金额'];
  238. }
  239. if ($memberInfo['amount'] < $data['coin_amt']) {
  240. return ['data' => '', 'code' => -154, 'msg' => '您的游戏平台币余额不足'];
  241. }
  242. $arrPayAmount = $payLogic->calCoinPayAmount($amount, $data['coin_amt'], $discount);
  243. }
  244. // 其他
  245. else{
  246. $arrPayAmount = $payLogic->calPayAmount($amount,0, $discount);
  247. }
  248. // // 全民付 替换其他支付
  249. // if (strstr($data['paytype'], 'qmf_wxmp_h5')) {
  250. // if ($data['paytype'] == 'qmf_wxmp_h5') {
  251. // $data['paytype'] = 'yyyb_wx_h5';
  252. // } else if ($data['paytype'] == 'mix-qmf_wxmp_h5') {
  253. // $data['paytype'] = 'mix-yyyb_wx_h5';
  254. // } else if ($data['paytype'] == 'coin-qmf_wxmp_h5') {
  255. // $data['paytype'] = 'coin-yyyb_wx_h5';
  256. // }
  257. // }
  258. // // ## 支付方式适配 -- 未使用
  259. // if (strstr($data['paytype'], 'pay_h5_001')) { // 备用支付 - 001
  260. // if ($data['paytype'] == 'pay_h5_001') {
  261. // $data['paytype'] = 'test';
  262. // } else if($data['paytype'] == 'mix-pay_h5_001'){
  263. // $data['paytype'] = 'mix-test';
  264. // } else if($data['paytype'] == 'coin-pay_h5_001'){
  265. // $data['paytype'] = 'coin-test';
  266. // }
  267. // }
  268. // if (strstr($data['paytype'], 'pay_h5_002')) { // 备用支付 - 002
  269. // if ($data['paytype'] == 'pay_h5_002') {
  270. // $data['paytype'] = 'test';
  271. // } else if($data['paytype'] == 'mix-pay_h5_002'){
  272. // $data['paytype'] = 'mix-test';
  273. // } else if($data['paytype'] == 'coin-pay_h5_002'){
  274. // $data['paytype'] = 'coin-test';
  275. // }
  276. // }
  277. // 实际支付金额为0时
  278. if ($arrPayAmount['real_amount'] == 0) {
  279. $pay_status = 1; // 支付成功
  280. $cp_payflag = 1;
  281. $payData['pay_time'] = NOW_TIMESTAMP; // 付款时间
  282. }
  283. // 有实际支付金额并且支付方式是平台币时
  284. elseif ($arrPayAmount['real_amount'] > 0 && $data['paytype'] == 'ptb') {
  285. return ['data' => '', 'code' => -160, 'msg' => '平台币余额不足,请使用混合支付'];
  286. } elseif ($arrPayAmount['real_amount'] > 0 && $arrPayAmount['real_ptb'] > 0 && substr($data['paytype'], 0, 4) <> 'mix-') {
  287. return ['data' => '', 'code' => -161, 'msg' => '请选择正确的支付方式.'];
  288. } // 有实际支付金额并且支付方式是平台币时
  289. elseif ($arrPayAmount['real_amount'] > 0 && $data['paytype'] == 'coinPay') {
  290. return ['data' => '', 'code' => -162, 'msg' => '平台币余额不足,请使用混合支付'];
  291. } elseif ($arrPayAmount['real_amount'] > 0 && $arrPayAmount['real_coin'] > 0 && substr($data['paytype'], 0, 5) <> 'coin-') {
  292. return ['data' => '', 'code' => -163, 'msg' => '可支付额度不足!'];
  293. }
  294. //指定时间内,禁止重复下单
  295. if (!requestDuplicateCheck('pay_duplicate_' . $data['member_id'] . '_' . $data['gameid'], $this->payRequestLimit)) {
  296. return ['data' => '', 'code' => -170, 'msg' => '充值请求过多,请于' . $this->payRequestLimit . 's以后,再次进行充值操作'];
  297. }
  298. //订单已重复
  299. if ($payModel->where(['attach' => $data['attach'], 'gameid' => $data['gameid']])->find()) {
  300. //解锁
  301. requestDuplicateCheckUnlock('pay_duplicate_' . $data['member_id'] . '_' . $data['gameid']);
  302. return ['data' => '', 'code' => -171, 'msg' => '游戏合作方的订单参数不能重复'];
  303. }
  304. //游戏防沉迷限制
  305. $authentication = (new CommonService())->authentication($data['member_id'], $data['gameid'], $data['amount']);
  306. if ($authentication['code'] == 0) {
  307. return $authentication;
  308. }
  309. // //海外支付添加比例
  310. // if (in_array($data['paytype'], ['airwallexh5', 'airwallex', 'coin-airwallexh5', 'coin-airwallex'])) {
  311. // $airPaytype = $data['paytype'];
  312. // if ($data['paytype'] == 'coin-airwallexh5') {
  313. // $airPaytype = 'airwallexh5';
  314. // } elseif ($data['paytype'] == 'coin-airwallex') {
  315. // $airPaytype = 'airwallex';
  316. // }
  317. // $paytypeInfo = model('common/PayType')->where('paytype', $airPaytype)->find();
  318. // // $arrPayAmount['real_amount'] = priceFormat($arrPayAmount['real_amount'] * (1 + $paytypeInfo['commission']));
  319. //
  320. // $commission_rate = bcadd('1', (string)$paytypeInfo['commission'], 4);
  321. // $arrPayAmount['real_amount'] = bcmul((string)$arrPayAmount['real_amount'], $commission_rate, 2);
  322. // }
  323. //订单参数
  324. $payData = $this->orderData($data, $arrPayAmount, $memberInfo, $gameInfo, $pay_status);
  325. // 订单超时时间(秒),默认5分钟;
  326. $pay_timeout = model("Setting")->getSetting('order_pay_timeout')??300;
  327. // 启动事务
  328. Db::startTrans();
  329. try {
  330. $id = $payModel->insertGetId($payData);
  331. //如果是自己聚合自己时,支付回调地址固定
  332. if (mb_substr($data['attach'], 0, 8, 'UTF-8') == 'xkhyn###') {
  333. $cpurl = Config::get('self_complex_callback_url');
  334. $attach = str_replace("xkhyn###", "", $data['attach']); //聚合的订单编号,去掉[aoyou###]前缀
  335. } else {
  336. $attach = $data['attach'];
  337. }
  338. //给Cp的用户名用子账号名
  339. $paycp_username = (!empty($data['sub_username']) ? $data['sub_username'] : $memberInfo['username']);
  340. // ## 订单回调签名 ##
  341. $str = "orderid=" . urlencode($orderid) . "&username=" . urlencode($paycp_username) . "&gameid=" . $data['gameid'] . "&roleid=" . urlencode($data['roleid']) . "&serverid=" . urlencode($data['serverid']) . "&paytype=" . urlencode($data['paytype']) . "&amount=" . $data['amount'] . "&paytime=" . $time . "&attach=" . urlencode($attach);
  342. $param = $str . "&appkey=" . urlencode($data['appInfo']['appkey']);
  343. $md5params = md5($param);
  344. $params = $str . "&sign=" . urlencode($md5params);
  345. // 订单通知游戏数据
  346. // log_message('order_id: ' . $orderid .' - URL: '. $cpurl ." - sign_data: ".$param. " - md5: ". $md5params, 'log', LOG_PATH . 'notify_msg/');
  347. trace('CP_SIGN - order_id: ' . $orderid .' - URL: '. $cpurl ." - sign_data: ".$param. " - md5: ". $md5params, 'GamePayService@gamePay.cp_notify_body');
  348. $paycpData['orderid'] = $orderid;
  349. $paycpData['fcallbackurl'] = $cpurl;
  350. $paycpData['params'] = $params;
  351. $paycpData['create_time'] = $time;
  352. $paycpData['payflag'] = $cp_payflag;
  353. $paycpData['pay_timeout'] = time() + $pay_timeout; // 订单超时时间
  354. //写入cy_paycpinfo表数据
  355. $payCpinfoModel->insert($paycpData);
  356. //代金券状态修改
  357. if ($payData['coupon_amount'] > 0) {
  358. if(!$payLogic->saveCouponData($payData)){
  359. // return ['data' => '', 'code' => -180, 'msg' => '代金券使用失败'];
  360. throw new \Exception('代金券使用失败', -180);
  361. }
  362. }
  363. // 如果使用了专属币
  364. if ($arrPayAmount['real_ptb'] > 0) {
  365. $payLogic->saveCoinData($userCoinInfo, $payData);
  366. } else if ($arrPayAmount['real_coin'] > 0) {
  367. if (!$payLogic->saveCoinPayData($memberInfo, $payData)) {
  368. // return ['data' => '', 'code' => -180, 'msg' => '金额异常.'];
  369. throw new \Exception('金额异常', -180);
  370. }
  371. }else if($payData['paytype'] == 'coupon'){
  372. // 纯代金券支付
  373. }else {
  374. // $arrPayAmount = $payLogic->calPayAmount($payData['pay_amount']);
  375. // if ($arrPayAmount['real_amount'] <= 0) {
  376. // return ['data' => '', 'code' => 0, 'msg' => '金额异常..'];
  377. // }
  378. }
  379. // $real_amount = $arrPayAmount['real_amount'];
  380. //全部平台币支付,并且支付成功时
  381. if ($pay_status) {
  382. //更新member表的total_pay_amount
  383. $memberModel->where(['id' => $data['member_id']])->update(['total_pay_amount' => Db::raw('total_pay_amount+' . $data['amount']), 'update_time' => time()]);
  384. }
  385. // 提交事务
  386. Db::commit();
  387. } catch (\Exception $e) {
  388. // 回滚事务
  389. Db::rollback();
  390. $eCode = $e->getCode();
  391. $eMess = $e->getMessage();
  392. if($eCode >= 0){
  393. $eCode = -190;
  394. $eMess = '订单创建失败: ' . $e->getMessage();
  395. }
  396. return ['data' => '', 'code' => $eCode, 'msg' => $eMess];
  397. } catch (\Error $e) {
  398. // 系统错误:代码bug,记录日志,给通用提示
  399. Db::rollback();
  400. return ['code' => -500, 'msg' => '订单系统异常:'. $e->getMessage(), 'data' => ''];
  401. }
  402. /**
  403. * 微信支付:
  404. * 可用:'qzl_wx_h5', 'ybzf_wxmp_h5', 'yyyb_wx_h5', 'xty_wx_h5'
  405. * 不可用:'ldys_wx_h5'
  406. *
  407. * 支付宝:
  408. * 可用:'xty_ali_h5', 'yyyb_ali_h5'
  409. * 不可用:'old-zfb-wap', 'ldys_zfb_h5'
  410. */
  411. $result = [];
  412. try {
  413. $device = Request::instance()->header('device', 0, 'intval');
  414. //第三方支付用的商品简单描述 (去除&+等特殊字符)
  415. $payBody = preg_replace("/[\&\+]+/", '', $data['productname']);
  416. $pay = new PayService();
  417. $real_amount = $payData['real_amount'];
  418. if($real_amount > 0){
  419. $payInfoRes = [];
  420. if (in_array($data['paytype'], ['zfb', 'coin-zfb', 'mix-zfb', 'coin-mix-zfb'])) { // 支付宝-app
  421. $notify_url = Config::get('ali_pay_config')['notify_url'];
  422. $payInfoRes = $pay->getAlipayAopParam($orderid, $real_amount, $payBody, '', $notify_url);
  423. } elseif (in_array($data['paytype'], ['old-zfb-wap', 'coin-old-zfb-wap', 'mix-old-zfb-wap', 'coin-mix-old-zfb-wap'])) { // 支付宝-h5
  424. $notify_url = Config::get('ali_pay_config')['notify_url'];
  425. $httpType = "POST";
  426. if($device == 4){
  427. $httpType = "GET";
  428. }
  429. $payInfoRes = $pay->getAlipayWapPostAopParam($orderid, $real_amount, $payBody, '', $notify_url, $httpType);
  430. if(empty($payInfoRes['data']['mweb_url'])){
  431. return ['data' => '', 'code' => -200, 'msg' => "当前支付方式开发中..."];
  432. }
  433. } elseif (in_array($data['paytype'], ['wxpay-h5', 'coin-wxpay-h5', 'wx-wap', 'coin-wx-wap'])) { // 微信-h5
  434. if ($real_amount > 3000) {
  435. requestDuplicateCheckUnlock('pay_duplicate_' . $data['member_id'] . '_' . $data['gameid']);
  436. return ['data' => '', 'code' => -201, 'msg' => '微信单笔支付限额3000元,您可选择其它支付'];
  437. }
  438. $notify_url = Config::get('wxpay-h5')['notify_url'];
  439. $payInfoRes = $pay->getWxpayH5Param($orderid, $real_amount, $payBody, $data['ip'], $notify_url, $data['gameid']);
  440. } elseif (in_array($data['paytype'], ['ybzf_wxmp_h5', 'coin-ybzf_wxmp_h5', 'mix-ybzf_wxmp_h5'])) { // 易宝wxmp-h5
  441. $notify_url = Config::get('ybzf_pay')['notify_url'];
  442. $payInfoRes = $pay->getYbzfParam($data['paytype'], $orderid, $real_amount, $payBody, $notify_url);
  443. } elseif (in_array($data['paytype'], ['ldys_zfb_h5', 'coin-ldys_zfb_h5', 'mix-ldys_zfb_h5', 'ldys_wx_h5', 'coin-ldys_wx_h5', 'mix-ldys_wx_h5'])) { // 联动优势
  444. $payType = 'payZfbH5';
  445. if (in_array($data['paytype'], ['ldys_wx_h5', 'coin-ldys_wx_h5', 'mix-ldys_wx_h5'])) {
  446. $payType = 'payWxmpH5V2';
  447. }
  448. $payData['is_coin'] = 0;
  449. $payInfoRes = $pay->getldysParam($payData, $payType);
  450. } elseif (in_array($data['paytype'], ['qzl_wx_h5', 'coin-qzl_wx_h5', 'mix-qzl_wx_h5', 'qzl_ali_h5', 'coin-qzl_ali_h5', 'mix-qzl_ali_h5'])) { // 趣智连支付-H5
  451. $payData['notify_url'] = Config::get('qzl_pay')['notify_url'];
  452. if(in_array($data['paytype'], ['qzl_wx_h5', 'coin-qzl_wx_h5', 'mix-qzl_wx_h5'])){
  453. $payInfoRes = $pay->getqzlParam($payData, 'payWxH5');
  454. }else if(in_array($data['paytype'], ['qzl_ali_h5', 'coin-qzl_ali_h5', 'mix-qzl_ali_h5'])){
  455. $payInfoRes = $pay->getqzlParam($payData, 'payAliH5');
  456. }else{
  457. return ['data' => '', 'code' => -202, 'msg' => '当前支付方式类型异常!!!'];
  458. }
  459. } elseif (in_array($data['paytype'], ['yyyb_wx_h5', 'coin-yyyb_wx_h5', 'mix-yyyb_wx_h5', 'yyyb_ali_h5', 'coin-yyyb_ali_h5', 'mix-yyyb_ali_h5'])) { // 优亿支付-H5
  460. $payData['notify_url'] = Config::get('yyyb_pay')['notify_url'];
  461. $payType = 'WX_H5';
  462. if (in_array($data['paytype'], ['yyyb_ali_h5', 'coin-yyyb_ali_h5', 'mix-yyyb_ali_h5'])) {
  463. $payType = 'ALI_H5';
  464. }
  465. $payInfoRes = $pay->getYyYbPayParam($payData, $payType);
  466. } elseif (in_array($data['paytype'], ['xty_wx_h5', 'coin-xty_wx_h5', 'mix-xty_wx_h5', 'xty_ali_h5', 'coin-xty_ali_h5', 'mix-xty_ali_h5'])) { // 喜钛游支付-H5
  467. $payData['notify_url'] = Config::get('xty_pay')['notify']['notify_url'];
  468. $payType = 'payWxH5';
  469. if (in_array($data['paytype'], ['xty_ali_h5', 'coin-xty_ali_h5', 'mix-xty_ali_h5'])) {
  470. $payType = 'payAliH5';
  471. }
  472. $payInfoRes = $pay->getXtyPayParam($payData, $payType);
  473. } elseif (in_array($data['paytype'], ['syw_wx_h5', 'coin-syw_wx_h5', 'mix-syw_wx_h5'])) { // 十一玩-H5
  474. // , 'syw_ali_h5', 'coin-syw_ali_h5', 'mix-syw_ali_h5'
  475. $payData['notify_url'] = Config::get('syw_pay')['notify']['notify_url'];
  476. $payType = 'wxh5';
  477. // if (in_array($data['paytype'], ['xty_ali_h5', 'coin-xty_ali_h5', 'mix-xty_ali_h5'])) {
  478. // $payType = 'payAliH5';
  479. // }
  480. $payInfoRes = $pay->getSywPayParam($payData, $payType);
  481. } elseif (in_array($data['paytype'], ['test', 'coin-test', 'mix-test'])) {
  482. return ['data' => '', 'code' => -200, 'msg' => "当前支付方式开发中..."];
  483. }
  484. // dump($data['paytype'], $payInfoRes);
  485. // TODO: 新加支付方式时,这块判断要加上支付方式的返回判断。
  486. if ($payInfoRes && $data['paytype'] != 'coinpay') {
  487. if ($payInfoRes['error'] == true) {
  488. trace("支付方式下单失败 - {$data['paytype']}: " . json_encode($payInfoRes), 'GamePayService@gamePay.$payInfoRes');
  489. ddMsg("warning", '', ['支付方式-' . $data['paytype'], $payInfoRes['msg'], json_encode(['orderid' => $orderid, 'username' => $paycp_username, 'gameid' => $data['gameid']], JSON_UNESCAPED_UNICODE)]);
  490. return ['data' => '', 'code' => -210, 'msg' => "发起下单失败!(" . $data['paytype'] . ")"];
  491. }
  492. if (in_array($data['paytype'], ['zfb', 'coin-zfb', 'mix-zfb', 'coin-mix-zfb'])) {
  493. $result = ['alipay_app_param' => $payInfoRes['data'], 'wxpayh5_param' => ['mweb_url' => '']];
  494. } elseif (in_array($data['paytype'], [
  495. 'old-zfb-wap', 'coin-old-zfb-wap', 'mix-old-zfb-wap', 'coin-mix-old-zfb-wap',
  496. 'ldys_zfb_h5', 'coin-ldys_zfb_h5', 'mix-ldys_zfb_h5',
  497. 'yyyb_ali_h5', 'coin-yyyb_ali_h5', 'mix-yyyb_ali_h5',
  498. 'xty_ali_h5', 'coin-xty_ali_h5', 'mix-xty_ali_h5',
  499. 'qzl_ali_h5', 'coin-qzl_ali_h5', 'mix-qzl_ali_h5',
  500. ])) {
  501. $result = ['alipay_param' => $payInfoRes['data']];
  502. if($device == 4){
  503. $result = ['pay_url' => $payInfoRes['data']['mweb_url']];
  504. }
  505. } elseif (in_array($data['paytype'], [
  506. 'wxpay-h5', 'coin-wxpay-h5',
  507. 'wx-wap', 'coin-wx-wap',
  508. 'qzl_wx_h5', 'coin-qzl_wx_h5', 'mix-qzl_wx_h5',
  509. 'qmf_wxmp_h5', 'coin-qmf_wxmp_h5', 'mix-qmf_wxmp_h5',
  510. 'ybzf_wxmp_h5', 'coin-ybzf_wxmp_h5', 'mix-ybzf_wxmp_h5',
  511. 'ldys_wx_h5', 'coin-ldys_wx_h5', 'mix-ldys_wx_h5',
  512. 'yyyb_wx_h5', 'coin-yyyb_wx_h5', 'mix-yyyb_wx_h5',
  513. 'xty_wx_h5', 'coin-xty_wx_h5', 'mix-xty_wx_h5',
  514. 'syw_wx_h5', 'coin-syw_wx_h5', 'mix-syw_wx_h5',
  515. ])) {
  516. $result = ['wxpayh5_param' => $payInfoRes['data']];
  517. if($device == 4){
  518. $result = ['pay_url' => $payInfoRes['data']['mweb_url']];
  519. }
  520. } else {
  521. return ['data' => '', 'code' => -220, 'msg' => '支付渠道未配置返回类型!'];
  522. }
  523. }
  524. }
  525. requestDuplicateCheckUnlock('pay_duplicate_' . $data['member_id'] . '_' . $data['gameid']);
  526. } catch (Exception $e) {
  527. // 回滚事务
  528. // Db::rollback();
  529. return ['data' => '', 'code' => -230, 'msg' => '订单生成失败.:' . $e->getMessage()];
  530. }
  531. $result['pay_status'] = $pay_status; //支付状态
  532. $result['orderid'] = $orderid;
  533. $result['channel_id'] = $data['channel_id'];
  534. $result['paytype'] = $data['paytype'];
  535. $result['pay_timeout'] = time() + $pay_timeout; // 订单过期时间戳
  536. $result['pay_timeout_num'] = (int)$pay_timeout; // 订单过期时间秒数
  537. return ['data' => $result, 'code' => 1, 'msg' => '订单生成成功'];
  538. }
  539. /**
  540. * 订单参数
  541. * @param $data
  542. * @param $arrPayAmount
  543. * @param $memberInfo
  544. * @param $gameInfo
  545. */
  546. public function orderData($data, $arrPayAmount, $memberInfo, $gameInfo, $pay_status)
  547. {
  548. if ($arrPayAmount['real_amount'] > 0) {
  549. $real_amount = $arrPayAmount['real_amount'];
  550. } else {
  551. $real_amount = 0;
  552. }
  553. $payData['orderid'] = $data['orderid'];
  554. $payData['discount'] = $data['discount'] ?: 1;
  555. $payData['amount'] = $data['amount'];
  556. $payData['real_amount'] = $real_amount;
  557. $payData['real_ptb'] = $arrPayAmount['real_ptb'] ?: 0;
  558. $payData['real_coin'] = $arrPayAmount['real_coin'] ?: 0;
  559. $payData['coupon_amount'] = $data['coupon_amount'];
  560. // $payData['real_ptb_amount'] = $arrPayAmount['real_ptb_amount'];
  561. $payData['userid'] = $data['member_id'];
  562. $payData['username'] = $memberInfo['username'];
  563. $payData['roleid'] = $data['roleid'];
  564. $payData['rolename'] = $data['rolename'];
  565. $payData['rolelevel'] = $data['rolelevel'];
  566. $payData['paytype'] = $data['paytype'];
  567. $payData['productname'] = $data['productname'];
  568. $payData['serverid'] = $data['serverid'];
  569. $payData['servername'] = $data['servername'];
  570. $payData['gameid'] = $data['gameid'];
  571. $payData['status'] = $pay_status;
  572. $payData['ip'] = $data['ip'];
  573. $payData['imeil'] = $data['imeil'];
  574. $payData['create_time'] = NOW_TIMESTAMP;
  575. $payData['channel_id'] = $data['channel_id'];
  576. $payData['recheck_status'] = $gameInfo['order_recheck'];
  577. $payData['attach'] = $data['attach'];
  578. $payData['coupon_member_id'] = $data['coupon_member_id'];
  579. // ## 订单真实所需支付金额=(订单金额 - 代金券) * 折扣率
  580. $payData['pay_amount'] = $arrPayAmount['pay_amount'];
  581. $payData['client_type'] = $data['client_type'];
  582. return $payData;
  583. }
  584. }