Recharge.php 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285
  1. <?php
  2. namespace app\api\controller;
  3. use app\admin\library\Auth;
  4. use app\admin\model\PalmpaySplitAccountLog;
  5. use app\common\constants\BigData;
  6. use app\common\controller\Api;
  7. use app\common\library\Ip;
  8. use app\common\library\Rabbitmq;
  9. use app\common\library\Redis;
  10. use app\common\library\Ua;
  11. use app\common\service\ActiveShareService;
  12. use app\common\service\KuaifenService;
  13. use app\common\service\OrderService;
  14. use app\common\service\UserVipExtendService;
  15. use app\main\constants\ApiConstants;
  16. use app\main\constants\CacheConstants;
  17. use app\main\constants\KafkaDotConstants;
  18. use app\main\constants\PayConstants;
  19. use app\main\constants\UserConstants;
  20. use app\main\model\object\AnalysisObject;
  21. use app\main\service\AdminService;
  22. use app\main\service\BookService;
  23. use app\main\service\IpaynowPayService;
  24. use app\main\service\JoinPayService;
  25. use app\main\service\KafkaDotService;
  26. use app\main\service\LogService;
  27. use app\main\service\MihuaPayService;
  28. use app\main\service\MqUserPayCancelService;
  29. use app\main\service\OrderCollectService;
  30. use app\main\service\PalmPayService;
  31. use app\main\service\SpecialPayService;
  32. use app\main\service\UnsPayService;
  33. use app\main\service\UrlService;
  34. use app\main\service\UserService;
  35. use app\main\service\WeChatAdService;
  36. use EasyWeChat\Factory;
  37. use fast\Random;
  38. use Symfony\Component\Cache\Simple\RedisCache;
  39. use think\Config;
  40. use think\Cookie;
  41. use think\db\Query;
  42. use think\Exception;
  43. use think\Log;
  44. class Recharge extends Api
  45. {
  46. protected $wxNeedLogin = ['pay'];
  47. private function _initPayInfo()
  48. {
  49. Log::info('[ WeChat ] [ PAY ] [ CALLBACK ] GET: ' . json_encode(var_export($this->request->get(), true),
  50. JSON_UNESCAPED_UNICODE));
  51. Log::info('[ WeChat ] [ PAY ] [ CALLBACK ] INPUT: ' . json_encode(var_export($this->request->getInput(), true),
  52. JSON_UNESCAPED_UNICODE));
  53. $goods_id = $this->request->request('id'); // 商品id
  54. $admin_id = UserService::instance()->getAdminId()->data; // 渠道商/代理商id
  55. $channel_id = UserService::instance()->getUserChannelId()->data; //渠道商id
  56. $adminExtend = AdminService::instance()->getAdminExtendModel()->getInfo($admin_id);
  57. if ($adminExtend['distribute'] == '1') {
  58. //代理商配置信息
  59. $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($admin_id);
  60. } else {
  61. //渠道商配置信息
  62. $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($channel_id);
  63. }
  64. if (!$goods_id || !$admin_id) {
  65. $this->error('缺少参数');
  66. }
  67. $goodsCategory = $this->request->request('category'); //商品分类 nickname
  68. $activityId = $this->request->request('activityId', 0); //活动id
  69. $group = model('AuthGroupAccess')->where('uid', $admin_id)->find();
  70. $group_id = $group->group_id;
  71. if (!$goodsInfo = model('Goods')->getGoodsInfoById($goods_id)) {
  72. $this->error('商品不存在');
  73. }
  74. $goodsInfo['activity_id'] = $activityId;
  75. if ($this->request->param('buyMore')) {
  76. $configBuyMore = PayConstants::getBuyMore(UserService::instance()->getUserInfo()->id);
  77. if ($goodsInfo['money'] >= 1) {
  78. $goodsInfo['money'] = (int)$goodsInfo['money'];
  79. }
  80. $goodsInfo['money'] = (string)($goodsInfo['money'] * 100 / 100);
  81. if (array_key_exists($goodsInfo['money'], $configBuyMore)) {
  82. $goodsInfo['buy_id'] = $configBuyMore[$goodsInfo['money']]['id'];
  83. $goodsInfo['money'] += $configBuyMore[$goodsInfo['money']]['money'];
  84. }
  85. }
  86. /**
  87. * 未登录的逻辑处理
  88. */
  89. if (!$this->user->isLogin()) {
  90. $this->error('登录信息获取失败');
  91. }
  92. /**
  93. * 获取渠道商/代理商资料
  94. */
  95. if (!$adminExtend) {
  96. $this->error('管理员信息获取失败');
  97. }
  98. $channelExtend = $adminExtend;
  99. if ($group_id == 4) {
  100. //代理 获取渠道信息
  101. $channelExtend = AdminService::instance()->getAdminExtendModel()->where(['admin_id' => $channel_id])->find();
  102. }
  103. return [$goodsCategory, $goods_id, $admin_id, $goodsInfo, $adminExtend, $channel_id, $adminConfig, $group_id, $channelExtend];
  104. }
  105. /**
  106. * @param $payment 支付方式 0 微信;1 四方平台
  107. * @param $adminId
  108. * @param $adminExtend
  109. * @param $row
  110. * @param $goodsCategory
  111. * @param $pdOrderId
  112. * @param $out_trade_no
  113. * @param $goodsId
  114. * @param $payInfo
  115. * @param $channelId
  116. * @param $prepay_id
  117. * @param $groupId
  118. * @param $pay_json
  119. * @param $kl_admin_info
  120. * @throws \think\db\exception\DataNotFoundException
  121. * @throws \think\db\exception\ModelNotFoundException
  122. * @throws \think\exception\DbException
  123. */
  124. private function _createOrderInfo(
  125. $payment,
  126. $adminId,
  127. $adminExtend,
  128. $row,
  129. $goodsCategory,
  130. $pdOrderId,
  131. $out_trade_no,
  132. $goodsId,
  133. $payInfo,
  134. $channelId,
  135. $prepay_id,
  136. $groupId,
  137. $pay_json,
  138. $kl_admin_info,
  139. $channelExtend
  140. )
  141. {
  142. $user_id = UserService::instance()->getUserInfo()->id;
  143. if ($this->request->param('buyMore')) {
  144. LogService::info('PAYMOREORDER:' . $user_id . ':' . $out_trade_no);
  145. if (array_key_exists('buy_id', $row)) {
  146. Redis::instance()->set(CacheConstants::getBuyMoreOrderCache($out_trade_no), $row['buy_id'], 600);
  147. }
  148. }
  149. if ($this->request->param('single_push')) {
  150. LogService::info("SinglePush:" . $user_id . ":" . $out_trade_no);
  151. $sbookId = $this->request->param('book_id');
  152. Redis::instance()->set(CacheConstants::getSinglePushOrderCache($out_trade_no), $sbookId, 600);
  153. }
  154. $insertData = [
  155. 'user_id' => $user_id,
  156. 'admin_id' => $adminId,
  157. 'benefit' => $adminExtend['benefit'],
  158. 'money' => $row['money'],
  159. 'money_benefit' => round($row['money'] * $adminExtend['benefit'], 2),
  160. 'category' => $goodsCategory,
  161. 'payid' => $prepay_id,
  162. 'out_trade_no' => $out_trade_no,
  163. 'ip' => Ip::ip(),
  164. 'referral_id' => UrlService::instance()->getUserReferralId()->data,
  165. 'referral_id_permanent' => UserService::instance()->getUserInfo()->referral_id_permanent,
  166. 'book_id' => $this->request->request('book_id'),
  167. 'chapter_id' => $this->request->request('chapter_id'),
  168. 'goods_id' => $goodsId,
  169. 'kandian' => $row['kandian'],
  170. 'free_kandian' => $row['free_kandian'],
  171. 'day' => $row['day'],
  172. 'type' => $row['type'],
  173. 'state' => 0,
  174. 'business_line' => $this->request->param('business') ?? 0,
  175. 'pay_json' => $pay_json,
  176. 'activity_id' => $row['activity_id'],
  177. 'payment_method' => $payment,
  178. 'wxpay_id' => $payInfo['id'],
  179. 'ext' => UserService::instance()->getUserInfo()->ext && json_decode(UserService::instance()->getUserInfo()->ext) ? UserService::instance()->getUserInfo()->ext : json_encode(new \stdClass()),
  180. 'createtime' => time(),
  181. 'updatetime' => time(),
  182. 'channel_id' => $channelId,
  183. 'channel_benefit' => $channelExtend['benefit'],
  184. 'group' => $groupId,
  185. ];
  186. if ($payment == ApiConstants::PAYMENT_METHOD_PALM) {
  187. $insertData['pdorderid'] = $pdOrderId; //四方平台订单号
  188. }
  189. try {
  190. if ($kl_admin_info) {
  191. if ($kl_admin_info['admin_id'] != $channelId) {
  192. $insertData['deduct'] = 1;
  193. }
  194. $insertData['benefit'] = $kl_admin_info['benefit'];
  195. $insertData['money_benefit'] = round($row['money'] * $kl_admin_info['benefit'], 2);
  196. $insertData['admin_id'] = $kl_admin_info['admin_id'];
  197. $insertData['resource_id'] = $adminId;
  198. $adminId = $kl_admin_info->admin_id;
  199. $groupId = 3;
  200. $insertData['group'] = $groupId;
  201. }
  202. } catch (\Exception $e) {
  203. Log::error('订单扣量失败, Error:' . $e->getMessage());
  204. }
  205. //转移订单结束
  206. //如果订单没有扣量也没有转移,判断订单是否有赏金
  207. if (empty($insertData['deduct']) && empty($insertData['resource_id'])
  208. && $groupId == 4 && !empty($adminExtend['invite_id'])) {
  209. $invite_admin = model('AdminExtend')->where(['admin_id' => $adminExtend['invite_id']])->find();
  210. $admin_agent = model('Admin')->where('id', $adminExtend['invite_id'])->find();
  211. if ($invite_admin && $admin_agent['status'] == 'normal') {
  212. $insertData['reward_money'] = round($row['money'] * $invite_admin['reward_benefit'], 2);
  213. $insertData['reward_admin_id'] = $adminExtend['invite_id'];
  214. $insertData['reward_benefit'] = $invite_admin['reward_benefit'];
  215. }
  216. }
  217. $ordersId = model('Orders')->insertGetId($insertData);
  218. if (empty($insertData['deduct']) && $this->request->request('float_id')) {
  219. Redis::instance()->set(CacheConstants::getFloatTipsOrderId($ordersId), $this->request->request('float_id'));
  220. }
  221. if (!$ordersId) {
  222. $this->error('订单创建失败');
  223. } else {//如果订单存在 插入订单关联表
  224. if ($this->request->has('orderExtendType')) {//消耗活动
  225. $order_extend['order_id'] = $ordersId;
  226. $order_extend['type'] = $this->request->request('orderExtendType');
  227. $order_extend['created_at'] = date('Y-m-d H:i:s', time());
  228. $campaignArr = [];
  229. if ($order_extend['type'] == 1) {
  230. $campaignArr['campaign']['match_date'] = $this->request->request('campMatchDate');
  231. $campaignArr['campaign']['kandian'] = $this->request->request('campKandian');
  232. } elseif ($order_extend['type'] == 2) {
  233. $campaignArr['act_id'] = $this->request->request('actId');
  234. $campaignArr['sub_code'] = $this->request->request('subCode', 0);
  235. }
  236. $order_extend['json'] = json_encode($campaignArr);
  237. model('ordersExtend')->insert($order_extend);
  238. }
  239. }
  240. #region 快分app订单
  241. KuaifenService::instance()->createKuaifenOrders($ordersId, $insertData['admin_id'], $user_id,
  242. $insertData['book_id'], $insertData['money'], $insertData['out_trade_no']);
  243. #endregion
  244. //判断是充值vip还是充值书币
  245. $isVip = false;
  246. if (!empty($row['day'])) {
  247. $isVip = true;
  248. }
  249. $isActivity = !empty($row['activity_id']);
  250. if (empty($insertData['deduct'])) { //如果不是KL
  251. $channel_id = UserService::instance()->getUserChannelId()->data;
  252. OrderCollectService::instance()->addCreateOrderCollect($user_id, $adminId, $isVip, $channel_id, $groupId, PayConstants::BUSINESS_WECHAT, $isActivity);
  253. if ($isActivity) {
  254. $oAna = new AnalysisObject();
  255. $oAna->type = KafkaDotConstants::TYPE_ACTIVITY;
  256. $oAna->user_from = [
  257. 'activity_id' => $row['activity_id']
  258. ];
  259. $oAna->data = [
  260. 'stage' => 'start'
  261. ];
  262. KafkaDotService::instance()->sendMsg($user_id, $oAna);
  263. }
  264. } else {
  265. OrderCollectService::instance()->addCreateOrderCollect($user_id, $kl_admin_info['admin_id'], $isVip,
  266. $kl_admin_info['admin_id'], $groupId, PayConstants::BUSINESS_WECHAT, $isActivity);
  267. }
  268. }
  269. /**
  270. * 支付下单总入口
  271. */
  272. public function pay()
  273. {
  274. //默认官方支付
  275. $payment_method = 0;
  276. //根据域名进行匹配
  277. $host = get_host_no_port();
  278. $payHosts = model('Wxpay')->getHosts();
  279. if (in_array($host, $payHosts)) {
  280. //支付域名匹配成功
  281. $pay_hosts = model('Wxpay')->getInfoByHost($host);
  282. $payInfo = model('Wxpay')->getInfo($pay_hosts['platform_id'], $pay_hosts['id']);
  283. if (isset($payInfo['payment_method']) && $payInfo['payment_method'] > 0) {
  284. $payment_method = $payInfo['payment_method'];
  285. }
  286. } else {
  287. //支付域名匹配失败,从Cookie获取渠道默认支付方式
  288. $adminId = UserService::instance()->getAdminId()->data; // 渠道商/代理商ID
  289. $channel_id = UserService::instance()->getUserChannelId()->data;
  290. $adminExtend = AdminService::instance()->getAdminExtendModel()->where(['admin_id' => $adminId])->find();
  291. if ($adminExtend['distribute'] == '1') {
  292. //代理商配置信息
  293. $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($adminId);
  294. } else {
  295. //渠道商配置信息
  296. $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($channel_id);
  297. }
  298. // $adminConfig = AdminService::instance()->getAdminConfigModel()->getAdminInfoAll($adminId);
  299. if (isset($adminConfig['payment_method']) && $adminConfig['payment_method'] > 0) {
  300. $payment_method = $adminConfig['payment_method'];
  301. }
  302. }
  303. if ($this->request->has('url_id')) {
  304. $url_id = $this->request->request('url_id');
  305. $user_id = UserService::instance()->getUserInfo()->id;
  306. $canPay = SpecialPayService::instance()->canPay($url_id, $user_id);
  307. if ($canPay['code'] != 200) {
  308. $this->error($canPay['msg']);
  309. }
  310. }
  311. // 保存用户IP地址信息到Redis,下单成功后用户画像打点使用
  312. $ip_redis_key = CacheConstants::USER_IP_PREFIX . Cookie::get('user_id');
  313. Redis::instance()->set(
  314. $ip_redis_key,
  315. json_encode([
  316. 'ip' => Ip::ip(),
  317. 'country' => Ip::country(Ip::ip()),
  318. 'province' => Ip::province(Ip::ip()),
  319. 'city' => Ip::city(Ip::ip()),
  320. 'ua' => Ua::getUa()
  321. ]),
  322. 300
  323. );
  324. $result = [];
  325. switch ($payment_method) {
  326. case ApiConstants::PAYMENT_METHOD_PALM://四方支付
  327. $result = $this->payPalm();
  328. break;
  329. case ApiConstants::PAYMENT_METHOD_JOIN://汇聚支付
  330. $result = $this->payJoin();
  331. break;
  332. case ApiConstants::PAYMENT_METHOD_MIHUA://米花支付
  333. $result = $this->payMihua();
  334. break;
  335. case ApiConstants::PAYMENT_METHOD_UNS://银生宝支付
  336. $result = $this->payUns();
  337. break;
  338. case ApiConstants::PAYMENT_METHOD_IPAYNOW://现在支付
  339. $result = $this->payIpaynow();
  340. break;
  341. default://微信官方支付
  342. $result = $this->payWechat();
  343. break;
  344. }
  345. //更新订单号和用户id
  346. if ($this->request->has('url_id')) {
  347. SpecialPayService::instance()->updateUrl($url_id, ['user_id' => $user_id, 'out_trade_no' => $result['out_trade_no']]);
  348. }
  349. $this->success('订单创建成功', ['json' => $result['json']]);
  350. }
  351. public function payJoin()
  352. {
  353. list($goodsCategory, $goodsId, $adminId, $goodsInfo, $adminExtend, $channelId, $adminConfig, $groupId, $channelExtend)
  354. = $this->_initPayInfo();
  355. $pay_timeout = Config::has('site.pay_timeout') ? Config::get('site.pay_timeout') : 15;
  356. $payInfo = model('Wxpay')->getInfoByHost(get_host_no_port());
  357. $userId = Cookie::get('user_id');
  358. if ($pay_timeout) {
  359. $endTime = time() - intval($pay_timeout) * 60;
  360. $has_orders = model('orders')
  361. ->where([
  362. 'money' => $goodsInfo['money'],
  363. 'goods_id' => $goodsId,
  364. 'user_id' => $userId,
  365. // 'admin_id' => $adminId,
  366. 'state' => '0',
  367. 'wxpay_id' => $payInfo['id'],
  368. 'payment_method' => ApiConstants::PAYMENT_METHOD_JOIN
  369. ])
  370. ->where(function (Query $query) use ($adminId) {
  371. $query->where('admin_id', $adminId)
  372. ->whereOr('resource_id', $adminId);
  373. })
  374. ->where('createtime', '>', $endTime)
  375. ->find();
  376. } else {
  377. $has_orders = null;
  378. }
  379. if (!empty($has_orders)) { //如果用户已经在该代理商/渠道商下过该单
  380. $json = $has_orders['pay_json'];
  381. $out_trade_no = $has_orders['out_trade_no'];
  382. } else {
  383. $kl_admin_info = OrderService::instance()->getKlAdminInfo($groupId, $adminId, $channelId, [
  384. 'day' => $goodsInfo['day'],
  385. 'activity_id' => $goodsInfo['activity_id'],
  386. 'user_id' => Cookie::get('user_id'),
  387. 'book_id' => $this->request->request('book_id'),
  388. ])->data;
  389. $paymentApplication = Factory::payment(Config::get('wechat'));
  390. $paymentApplication['cache'] = new RedisCache(Redis::instanceCache());
  391. $out_trade_no = date('YmdHis') . '_' . $userId . '_' . Random::build('alnum', 4);
  392. $productName = $goodsInfo['type'] == 2 ? '充值VIP' : '充值书币';
  393. $data = [
  394. 'p0_Version' => ApiConstants::JOIN_PAY_VERSION,
  395. 'p1_MerchantNo' => $payInfo['quartet_merchant_id'],
  396. 'p2_OrderNo' => $out_trade_no,
  397. 'p3_Amount' => $goodsInfo['money'],
  398. 'p4_Cur' => '1',
  399. 'p9_NotifyUrl' => Config::get('site.scheme') . '://' . Api::PAY_CALLBACK_PREFIX . $payInfo['pay_host'] . '/api/wechat/joinpay',
  400. 'q1_FrpCode' => ApiConstants::JOIN_PAY_TYPE,
  401. 'q5_OpenId' => Cookie::get('openid'),
  402. 'q7_AppId' => $payInfo['appid'],
  403. ];
  404. $goods_des = Config::get('site.goodsdes');
  405. if ($goods_des) {
  406. $data['p6_ProductDesc'] = $productName . ' ' . $goods_des;
  407. } else {
  408. $data['p6_ProductDesc'] = $productName;
  409. }
  410. if (!empty($adminConfig['json']['authorizer_info']['nick_name'])) {
  411. if (empty($goods_des)) {
  412. $zfxx = $userId . '_' . $adminConfig['json']['authorizer_info']['nick_name'] . '_' . $productName;
  413. } else {
  414. $zfxx = $userId . '_' . $adminConfig['json']['authorizer_info']['nick_name'] . '_' . $productName . '_' . $goods_des;
  415. }
  416. } else {
  417. if (empty($goods_des)) {
  418. $zfxx = $userId . '_' . $productName;
  419. } else {
  420. $zfxx = $userId . '_' . $productName . '_' . $goods_des;
  421. }
  422. }
  423. $data['p5_ProductName'] = mb_substr($zfxx, 0, 120, 'utf-8');
  424. $secret = $payInfo['quartet_app_key'];
  425. $signStr = $data['p0_Version'] . $data['p1_MerchantNo'] . $data['p2_OrderNo'] . $data['p3_Amount'] . $data['p4_Cur'] . $data['p5_ProductName'] . $data['p6_ProductDesc'] . $data['p9_NotifyUrl'] . $data['q1_FrpCode'] . $data['q5_OpenId'] . $data['q7_AppId'] . $secret;
  426. $data['hmac'] = md5($signStr);
  427. $orderInfo = [
  428. 'goods_id' => $goodsId,
  429. 'out_trade_no' => $out_trade_no,
  430. 'admin_id' => $adminId,
  431. 'user_id' => $userId,
  432. ];
  433. $joinService = JoinPayService::instance();
  434. try {
  435. $result = $joinService->payJoinApi($data, $payInfo, $goodsInfo, $orderInfo);
  436. } catch (Exception $e) {
  437. $this->success($e->getMessage());
  438. }
  439. $payInfoArr = json_decode($result['rc_Result'], true);
  440. $prepay_id = explode('=', $payInfoArr['package'])[1];
  441. $this->_createOrderInfo(ApiConstants::PAYMENT_METHOD_JOIN, $adminId,
  442. $adminExtend,
  443. $goodsInfo,
  444. $goodsCategory,
  445. $result['r7_TrxNo'],
  446. $out_trade_no,
  447. $goodsId,
  448. $payInfo,
  449. $channelId,
  450. $prepay_id,
  451. $groupId,
  452. $result['rc_Result'],
  453. $kl_admin_info,
  454. $channelExtend
  455. );
  456. $json = $result['rc_Result'];
  457. }
  458. //下单订单数据统计
  459. return ['json' => $json, 'out_trade_no' => $out_trade_no];
  460. }
  461. /**
  462. * 微信下单
  463. */
  464. public function payWechat()
  465. {
  466. list($goodsCategory, $goodsId, $adminId, $row, $adminExtend, $channelId, $adminConfig, $groupId, $channelExtend)
  467. = $this->_initPayInfo();
  468. //本月
  469. $paymentApplication = Factory::payment(Config::get('wechat'));
  470. $paymentApplication['cache'] = new RedisCache(Redis::instanceCache());
  471. $pay_timeout = Config::has('site.pay_timeout') ? Config::get('site.pay_timeout') : 15;
  472. $payInfo = model('Wxpay')->getInfoByHost(get_host_no_port());
  473. $userId = Cookie::get('user_id');
  474. if ($pay_timeout) {
  475. $endTime = time() - intval($pay_timeout) * 60;
  476. $has_orders = model('orders')
  477. ->where([
  478. 'money' => $row['money'],
  479. 'goods_id' => $goodsId,
  480. 'user_id' => $userId,
  481. // 'admin_id' => $adminId,
  482. 'state' => '0',
  483. 'wxpay_id' => $payInfo['id'],
  484. 'payment_method' => ApiConstants::PAYMENT_METHOD_WECHAT
  485. ])
  486. ->where(function (Query $query) use ($adminId) {
  487. $query->where('admin_id', $adminId)
  488. ->whereOr('resource_id', $adminId);
  489. })
  490. ->where('createtime', '>', $endTime)
  491. ->find();
  492. } else {
  493. $has_orders = null;
  494. }
  495. if (!empty($has_orders)) { //如果用户已经在该代理商/渠道商下过该单
  496. $jssdk = $paymentApplication->jssdk;
  497. $json = $jssdk->bridgeConfig($has_orders['payid']);
  498. $out_trade_no = $has_orders['out_trade_no'];
  499. } else {
  500. $kl_admin_info = OrderService::instance()->getKlAdminInfo($groupId, $adminId, $channelId, [
  501. 'day' => $row['day'],
  502. 'activity_id' => $row['activity_id'],
  503. 'user_id' => Cookie::get('user_id'),
  504. 'book_id' => $this->request->request('book_id'),
  505. ])->data;
  506. $out_trade_no = date('YmdHis') . '_' . $userId . '_' . Random::build('alnum', 4);
  507. $data = [
  508. 'body' => $row['type'] == 2 ? '充值VIP' : '充值书币',
  509. 'out_trade_no' => $out_trade_no,
  510. 'total_fee' => $row['money'] * 100,
  511. 'spbill_create_ip' => Ip::ip(),
  512. 'notify_url' => Config::get('site.scheme') . '://' . Api::PAY_CALLBACK_PREFIX . $payInfo['pay_host'] . '/api/wechat/pay',
  513. // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  514. 'trade_type' => 'JSAPI',
  515. 'openid' => Cookie::get('openid'),
  516. ];
  517. $goods_des = Config::get('site.goodsdes');
  518. if ($goods_des) {
  519. $data['body'] = $data['body'] . ' ' . $goods_des;
  520. }
  521. if (!empty($adminConfig['json']['authorizer_info']['nick_name'])) {
  522. $zfxx = $adminConfig['json']['authorizer_info']['nick_name'] . '_' . $data['body'];
  523. $data['body'] = mb_substr($zfxx, 0, 120, 'utf-8');
  524. }
  525. $palmApiStartTime = microtime(true);
  526. $result = $paymentApplication->order->unify($data);
  527. $palmApiEndTime = microtime(true);
  528. $apiRunTime = round($palmApiEndTime - $palmApiStartTime, 3);
  529. if ($result['return_code'] == 'FAIL') {
  530. Log::error(sprintf('wechatpay_create_order_fail!wxpay_id:%s,wxpay_name:%s,mch_id:%s,channel_id:%s,user_id:%s,money:%s,good_id:%s,out_trade_no:%s,api_run_time:%s s,errmessage:%s'
  531. , $payInfo['id'], $payInfo['name'], $payInfo['mcid'], $adminId, $userId, $row['money'],
  532. $goodsId, $out_trade_no, $apiRunTime,
  533. json_encode(var_export($result, true), JSON_UNESCAPED_UNICODE)));
  534. Log::error('微信订单创建失败!订单内容: ' . json_encode(var_export($data, true),
  535. JSON_UNESCAPED_UNICODE) . " 微信返回内容: " . json_encode(var_export($result, true),
  536. JSON_UNESCAPED_UNICODE));
  537. $this->error('微信订单创建失败');
  538. }
  539. $result['prepay_id'] = $result['prepay_id'] ?? 0;
  540. $this->_createOrderInfo(ApiConstants::PAYMENT_METHOD_WECHAT, $adminId,
  541. $adminExtend,
  542. $row,
  543. $goodsCategory,
  544. 0,
  545. $out_trade_no,
  546. $goodsId,
  547. $payInfo,
  548. $channelId,
  549. $result['prepay_id'],
  550. $groupId,
  551. '',
  552. $kl_admin_info,
  553. $channelExtend
  554. );
  555. $jssdk = $paymentApplication->jssdk;
  556. $json = $jssdk->bridgeConfig($result['prepay_id']);
  557. Log::info(sprintf('wechatpay_create_order_success!wxpay_id:%s,wxpay_name:%s,mch_id:%s,channel_id:%s,user_id:%s,money:%s,good_id:%s,out_trade_no:%s,api_run_time:%s s'
  558. , $payInfo['id'], $payInfo['name'], $payInfo['mcid'], $adminId, $userId,
  559. $row['money'], $goodsId, $out_trade_no, $apiRunTime));
  560. }
  561. return ['json' => $json, 'out_trade_no' => $out_trade_no];
  562. }
  563. public function payPalm()
  564. {
  565. list($goodsCategory, $goodsId, $adminId, $goodsInfo, $adminExtend, $channelId, $adminConfig, $groupId, $channelExtend)
  566. = $this->_initPayInfo();
  567. $pay_timeout = Config::has('site.pay_timeout') ? Config::get('site.pay_timeout') : 15;
  568. $payInfo = model('Wxpay')->getInfoByHost(get_host_no_port());
  569. $userId = UserService::instance()->getUserInfo()->id;
  570. if ($pay_timeout) {
  571. $endTime = time() - intval($pay_timeout) * 60;
  572. $has_orders = model('orders')
  573. ->where([
  574. 'money' => $goodsInfo['money'],
  575. 'goods_id' => $goodsId,
  576. 'user_id' => $userId,
  577. // 'admin_id' => $adminId,
  578. 'state' => '0',
  579. 'wxpay_id' => $payInfo['id'],
  580. 'payment_method' => ApiConstants::PAYMENT_METHOD_PALM
  581. ])
  582. ->where(function (Query $query) use ($adminId) {
  583. $query->where('admin_id', $adminId)
  584. ->whereOr('resource_id', $adminId);
  585. })
  586. ->where('createtime', '>', $endTime)
  587. ->find();
  588. } else {
  589. $has_orders = null;
  590. }
  591. if (!empty($has_orders)) { //如果用户已经在该代理商/渠道商下过该单
  592. $json = $has_orders['pay_json'];
  593. $out_trade_no = $has_orders['out_trade_no'];
  594. } else {
  595. $kl_admin_info = OrderService::instance()->getKlAdminInfo($groupId, $adminId, $channelId, [
  596. 'day' => $goodsInfo['day'],
  597. 'activity_id' => $goodsInfo['activity_id'],
  598. 'user_id' => Cookie::get('user_id'),
  599. 'book_id' => $this->request->request('book_id'),
  600. ])->data;
  601. $paymentApplication = Factory::payment(Config::get('wechat'));
  602. $paymentApplication['cache'] = new RedisCache(Redis::instanceCache());
  603. $out_trade_no = date('YmdHis') . '_' . $userId . '_' . Random::build('alnum', 4);
  604. $productName = $goodsInfo['type'] == 2 ? '充值VIP' : '充值书币';
  605. $data = [
  606. 'mchId' => $payInfo['quartet_merchant_id'],
  607. 'outTradeNo' => $out_trade_no,
  608. 'appid' => $payInfo['quartet_app_id'],
  609. 'version' => ApiConstants::PALM_PAY_VERSION,
  610. 'money' => $goodsInfo['money'] * 100,
  611. 'ip' => Ip::ip(),
  612. 'notifyUrl' => Config::get('site.scheme') . '://' . Api::PAY_CALLBACK_PREFIX . $payInfo['pay_host'] . '/api/wechat/palmpay',
  613. // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  614. 'subAppid' => $payInfo['appid'],
  615. 'openid' => Cookie::get('openid'),
  616. ];
  617. $palmPayCmdDefault = null;
  618. if ($payInfo['quartet_is_split'] == ApiConstants::QUARTET_IS_SPLIT) {
  619. if ($kl_admin_info && $kl_admin_info['admin_id'] != $channelId) {
  620. //仅扣量订单全部到自家子账号
  621. $palmPayCmd = OrderService::instance()->getPalmPayCmd($goodsInfo['money'], 0)->data;
  622. $cmd = $palmPayCmd['cmd'];
  623. $palmPayCmdDefault = $palmPayCmd['default'];
  624. } else {
  625. $palmPayCmd = OrderService::instance()->getPalmPayCmd($goodsInfo['money'], $channelId)->data;
  626. $cmd = $palmPayCmd['cmd'];
  627. $palmPayCmdDefault = $palmPayCmd['default'];
  628. }
  629. if (!$cmd) {
  630. LogService::debug("微信分账设置错误");
  631. $this->success('订单创建失败,请重新下单!');
  632. }
  633. $data['cmd'] = $cmd;
  634. }
  635. $goods_des = Config::get('site.goodsdes');
  636. if ($goods_des) {
  637. $data['productName'] = urlencode($productName . ' ' . $goods_des);
  638. } else {
  639. $data['productName'] = urlencode($productName);
  640. }
  641. if (!empty($adminConfig['json']['authorizer_info']['nick_name'])) {
  642. if (empty($goods_des)) {
  643. $zfxx = $userId . '_' . $adminConfig['json']['authorizer_info']['nick_name'] . '_' . $productName;
  644. } else {
  645. $zfxx = $userId . '_' . $adminConfig['json']['authorizer_info']['nick_name'] . '_' . $productName . '_' . $goods_des;
  646. }
  647. $data['productDesc'] = mb_substr($zfxx, 0, 120, 'utf-8');
  648. $data['productDesc'] = urlencode($data['productDesc']);
  649. }
  650. $signStr = $payInfo['quartet_app_id'] . 'WECHAT_SUB' . $data['money'] . $data['outTradeNo'] . $payInfo['quartet_app_key'];
  651. $data['sign'] = md5($signStr);
  652. $orderInfo = [
  653. 'goods_id' => $goodsId,
  654. 'out_trade_no' => $out_trade_no,
  655. 'admin_id' => $adminId,
  656. 'user_id' => $userId,
  657. ];
  658. try {
  659. $result = PalmPayService::instance()->payPalmApi($data, $payInfo, $goodsInfo, $orderInfo);
  660. } catch (Exception $e) {
  661. $this->success($e->getMessage());
  662. }
  663. //分账记录日志
  664. if (!empty($palmPayCmdDefault)) {
  665. $channel_palmpay_sub_account_id = $palmPayCmdDefault['channel_palmpay_sub_account_id'];
  666. $channel_amount = $palmPayCmdDefault['channel_amount'];
  667. $dz_palmpay_sub_account_id = $palmPayCmdDefault['dz_palmpay_sub_account_id'];
  668. $dz_amount = $palmPayCmdDefault['dz_amount'];
  669. PalmpaySplitAccountLog::create([
  670. 'order_id' => $out_trade_no,
  671. 'dz_palmpay_sub_account_id' => $dz_palmpay_sub_account_id,
  672. 'dz_amount' => $dz_amount,
  673. 'channel_palmpay_sub_account_id' => $channel_palmpay_sub_account_id,
  674. 'channel_amount' => $channel_amount
  675. ])->insert();
  676. }
  677. $result = $result['result'];
  678. $payInfoArr = json_decode($result['pay_info'], true);
  679. $prepay_id = explode('=', $payInfoArr['package'])[1];
  680. $this->_createOrderInfo(ApiConstants::PAYMENT_METHOD_PALM, $adminId,
  681. $adminExtend,
  682. $goodsInfo,
  683. $goodsCategory,
  684. $result['pdorderid'],
  685. $out_trade_no,
  686. $goodsId,
  687. $payInfo,
  688. $channelId,
  689. $prepay_id,
  690. $groupId,
  691. $result['pay_info'],
  692. $kl_admin_info,
  693. $channelExtend
  694. );
  695. $json = $result['pay_info'];
  696. }
  697. //下单订单数据统计
  698. return ['json' => $json, 'out_trade_no' => $out_trade_no];
  699. }
  700. public function payMihua()
  701. {
  702. list($goodsCategory, $goodsId, $adminId, $goodsInfo, $adminExtend, $channelId, $adminConfig, $groupId, $channelExtend)
  703. = $this->_initPayInfo();
  704. $pay_timeout = Config::has('site.pay_timeout') ? Config::get('site.pay_timeout') : 15;
  705. $payInfo = model('Wxpay')->getInfoByHost(get_host_no_port());
  706. $userId = Cookie::get('user_id');
  707. if ($pay_timeout) {
  708. $endTime = time() - intval($pay_timeout) * 60;
  709. $has_orders = model('orders')
  710. ->where([
  711. 'money' => $goodsInfo['money'],
  712. 'goods_id' => $goodsId,
  713. 'user_id' => $userId,
  714. // 'admin_id' => $adminId,
  715. 'state' => '0',
  716. 'wxpay_id' => $payInfo['id'],
  717. 'payment_method' => ApiConstants::PAYMENT_METHOD_MIHUA
  718. ])
  719. ->where(function (Query $query) use ($adminId) {
  720. $query->where('admin_id', $adminId)
  721. ->whereOr('resource_id', $adminId);
  722. })
  723. ->where('createtime', '>', $endTime)
  724. ->find();
  725. } else {
  726. $has_orders = null;
  727. }
  728. if (!empty($has_orders)) { //如果用户已经在该代理商/渠道商下过该单
  729. $json = $has_orders['pay_json'];
  730. $out_trade_no = $has_orders['out_trade_no'];
  731. } else {
  732. $kl_admin_info = OrderService::instance()->getKlAdminInfo($groupId, $adminId, $channelId, [
  733. 'day' => $goodsInfo['day'],
  734. 'activity_id' => $goodsInfo['activity_id'],
  735. 'user_id' => Cookie::get('user_id'),
  736. 'book_id' => $this->request->request('book_id'),
  737. ])->data;
  738. $paymentApplication = Factory::payment(Config::get('wechat'));
  739. $paymentApplication['cache'] = new RedisCache(Redis::instanceCache());
  740. $out_trade_no = date('YmdHis') . '_' . $userId . '_' . Random::build('alnum', 4);
  741. $productName = $goodsInfo['type'] == 2 ? '充值VIP' : '充值书币';
  742. $userId = Cookie::get('user_id'); // 用户ID
  743. $user = model('User')->getUserInfo($userId);
  744. $createtimeTs = empty($user) ? time() : $user['createtime'];
  745. $createtimeStr = date('YmdHis', $createtimeTs);
  746. $aRiskItem = [
  747. 'userInfoMerchantNo' => $userId,
  748. 'userInfoDtRegister' => $createtimeStr,
  749. ];
  750. $data = [
  751. 'merAccount' => $payInfo['quartet_app_id'],
  752. 'merNo' => $payInfo['quartet_merchant_id'],
  753. 'orderId' => $out_trade_no,
  754. 'time' => time(),
  755. 'amount' => (int)($goodsInfo['money'] * 100),
  756. 'payWay' => 'WEIXIN',
  757. 'payType' => 'JSAPI_WEIXIN',
  758. 'userIp' => Ip::ip(),
  759. 'openId' => Cookie::get('openid'),
  760. 'returnUrl' => 'http://www.baidu.com',//前端页面回调地址
  761. 'notifyUrl' => Config::get('site.scheme') . '://' . Api::PAY_CALLBACK_PREFIX . $payInfo['pay_host'] . '/api/wechat/mihuapay',
  762. 'riskItem' => json_encode($aRiskItem),
  763. ];
  764. $goods_des = Config::get('site.goodsdes');
  765. if ($goods_des) {
  766. $data['productDesc'] = $productName . ' ' . $goods_des;
  767. } else {
  768. $data['productDesc'] = $productName;
  769. }
  770. if (!empty($adminConfig['json']['authorizer_info']['nick_name'])) {
  771. if (empty($goods_des)) {
  772. $zfxx = $userId . '丨' . $adminConfig['json']['authorizer_info']['nick_name'] . '丨' . $productName;
  773. } else {
  774. $zfxx = $userId . '丨' . $adminConfig['json']['authorizer_info']['nick_name'] . '丨' . $productName . '丨' . $goods_des;
  775. }
  776. } else {
  777. if (empty($goods_des)) {
  778. $zfxx = $userId . '丨' . $productName;
  779. } else {
  780. $zfxx = $userId . '丨' . $productName . '丨' . $goods_des;
  781. }
  782. }
  783. $data['product'] = mb_substr($zfxx, 0, 120, 'utf-8');
  784. $mihuaService = MihuaPayService::instance($payInfo['quartet_app_key'],
  785. $payInfo['quartet_app_public_key']);
  786. $data['sign'] = $mihuaService->getSign($data);
  787. Log::info('米花支付请求参数:' . json_encode($data));
  788. $encode_data = $mihuaService->encrypt($data);
  789. $postData = array(
  790. 'merAccount' => $payInfo['quartet_app_id'],//商户标识
  791. 'data' => $encode_data
  792. );
  793. $orderInfo = [
  794. 'goods_id' => $goodsId,
  795. 'out_trade_no' => $out_trade_no,
  796. 'admin_id' => $adminId,
  797. 'user_id' => $userId,
  798. ];
  799. try {
  800. $result = $mihuaService->payMihuaApi($postData, $data, $payInfo, $goodsInfo, $orderInfo);
  801. } catch (Exception $e) {
  802. $this->success($e->getMessage());
  803. }
  804. $prepay_id = $result['data']['mbOrderId'];
  805. $this->_createOrderInfo(ApiConstants::PAYMENT_METHOD_MIHUA, $adminId,
  806. $adminExtend,
  807. $goodsInfo,
  808. $goodsCategory,
  809. 0,
  810. $out_trade_no,
  811. $goodsId,
  812. $payInfo,
  813. $channelId,
  814. $prepay_id,
  815. $groupId,
  816. $result['data']['payInfo'],
  817. $kl_admin_info,
  818. $channelExtend
  819. );
  820. $json = $result['data']['payInfo'];
  821. }
  822. return ['json' => $json, 'out_trade_no' => $out_trade_no];
  823. }
  824. public function payUns()
  825. {
  826. list($goodsCategory, $goodsId, $adminId, $goodsInfo, $adminExtend, $channelId, $adminConfig, $groupId, $channelExtend)
  827. = $this->_initPayInfo();
  828. $pay_timeout = Config::has('site.pay_timeout') ? Config::get('site.pay_timeout') : 15;
  829. $payInfo = model('Wxpay')->getInfoByHost(get_host_no_port());
  830. $userId = Cookie::get('user_id');
  831. if ($pay_timeout) {
  832. $endTime = time() - intval($pay_timeout) * 60;
  833. $has_orders = model('orders')
  834. ->where([
  835. 'money' => $goodsInfo['money'],
  836. 'goods_id' => $goodsId,
  837. 'user_id' => $userId,
  838. // 'admin_id' => $adminId,
  839. 'state' => '0',
  840. 'wxpay_id' => $payInfo['id'],
  841. 'payment_method' => ApiConstants::PAYMENT_METHOD_UNS
  842. ])
  843. ->where(function (Query $query) use ($adminId) {
  844. $query->where('admin_id', $adminId)
  845. ->whereOr('resource_id', $adminId);
  846. })
  847. ->where('createtime', '>', $endTime)
  848. ->find();
  849. } else {
  850. $has_orders = null;
  851. }
  852. if (!empty($has_orders)) { //如果用户已经在该代理商/渠道商下过该单
  853. $json = $has_orders['pay_json'];
  854. $out_trade_no = $has_orders['out_trade_no'];
  855. } else {
  856. $kl_admin_info = OrderService::instance()->getKlAdminInfo($groupId, $adminId, $channelId, [
  857. 'day' => $goodsInfo['day'],
  858. 'activity_id' => $goodsInfo['activity_id'],
  859. 'user_id' => Cookie::get('user_id'),
  860. 'book_id' => $this->request->request('book_id'),
  861. ])->data;
  862. $paymentApplication = Factory::payment(Config::get('wechat'));
  863. $paymentApplication['cache'] = new RedisCache(Redis::instanceCache());
  864. $out_trade_no = date('YmdHis') . $userId . Random::build('alnum', 4);
  865. $productName = $goodsInfo['type'] == 2 ? '充值VIP' : '充值书币';
  866. $data = [
  867. 'accountId' => $payInfo['quartet_app_id'],
  868. 'orderId' => $out_trade_no,
  869. 'amount' => $goodsInfo['money'],
  870. 'responseUrl' => 'http://' . Api::PAY_CALLBACK_PREFIX . $payInfo['pay_host'] . '/api/wechat/unspay',
  871. 'openId' => Cookie::get('openid'),
  872. 'version' => '1.0.1',
  873. ];
  874. $goodsDes = Config::get('site.goodsdes');
  875. if ($goodsDes) {
  876. $data['commodity'] = $productName . ' ' . $goodsDes;
  877. } else {
  878. $data['commodity'] = $productName;
  879. }
  880. if (!empty($adminConfig['json']['authorizer_info']['nick_name'])) {
  881. if (empty($goods_des)) {
  882. $zfxx = $userId . '丨' . $adminConfig['json']['authorizer_info']['nick_name'] . '丨' . $productName;
  883. } else {
  884. $zfxx = $userId . '丨' . $adminConfig['json']['authorizer_info']['nick_name'] . '丨' . $productName . '丨' . $goods_des;
  885. }
  886. } else {
  887. if (empty($goods_des)) {
  888. $zfxx = $userId . '丨' . $productName;
  889. } else {
  890. $zfxx = $userId . '丨' . $productName . '丨' . $goods_des;
  891. }
  892. }
  893. $unsPayService = UnsPayService::instance($payInfo['quartet_app_key']);
  894. $data['subject'] = mb_substr($zfxx, 0, 120, 'utf-8');
  895. $data['mac'] = $unsPayService->makeMacParams($data);
  896. $orderInfo = [
  897. 'goods_id' => $goodsId,
  898. 'out_trade_no' => $out_trade_no,
  899. 'admin_id' => $adminId,
  900. 'user_id' => $userId,
  901. ];
  902. try {
  903. $result = $unsPayService->payUnsApi($data, $payInfo, $goodsInfo, $orderInfo);
  904. } catch (Exception $e) {
  905. $this->success($e->getMessage());
  906. }
  907. $strmPackage = $result['mPackage'];
  908. $amPackage = explode('=', $strmPackage);
  909. $prepayId = $amPackage[1];
  910. $payJson = UnsPayService::makeJsJsonParam($result);
  911. $this->_createOrderInfo(ApiConstants::PAYMENT_METHOD_UNS, $adminId,
  912. $adminExtend,
  913. $goodsInfo,
  914. $goodsCategory,
  915. 0,
  916. $out_trade_no,
  917. $goodsId,
  918. $payInfo,
  919. $channelId,
  920. $prepayId,
  921. $groupId,
  922. $payJson,
  923. $kl_admin_info,
  924. $channelExtend
  925. );
  926. $json = $payJson;
  927. }
  928. return ['json' => $json, 'out_trade_no' => $out_trade_no];
  929. }
  930. public function payIpaynow()
  931. {
  932. list($goodsCategory, $goodsId, $adminId, $goodsInfo, $adminExtend, $channelId, $adminConfig, $groupId, $channelExtend)
  933. = $this->_initPayInfo();
  934. $pay_timeout = Config::has('site.pay_timeout') ? Config::get('site.pay_timeout') : 15;
  935. $payInfo = model('Wxpay')->getInfoByHost(get_host_no_port());
  936. $userId = Cookie::get('user_id');
  937. if ($pay_timeout) {
  938. $endTime = time() - intval($pay_timeout) * 60;
  939. $has_orders = model('orders')
  940. ->where([
  941. 'money' => $goodsInfo['money'],
  942. 'goods_id' => $goodsId,
  943. 'user_id' => $userId,
  944. // 'admin_id' => $adminId,
  945. 'state' => '0',
  946. 'wxpay_id' => $payInfo['id'],
  947. 'payment_method' => ApiConstants::PAYMENT_METHOD_IPAYNOW
  948. ])
  949. ->where(function (Query $query) use ($adminId) {
  950. $query->where('admin_id', $adminId)
  951. ->whereOr('resource_id', $adminId);
  952. })
  953. ->where('createtime', '>', $endTime)
  954. ->find();
  955. } else {
  956. $has_orders = null;
  957. }
  958. if (!empty($has_orders)) {//如果用户已经在该代理商/渠道商下过该单
  959. $json = $has_orders['pay_json'];
  960. $out_trade_no = $has_orders['out_trade_no'];
  961. } else {
  962. $kl_admin_info = OrderService::instance()->getKlAdminInfo($groupId, $adminId, $channelId, [
  963. 'day' => $goodsInfo['day'],
  964. 'activity_id' => $goodsInfo['activity_id'],
  965. 'user_id' => Cookie::get('user_id'),
  966. 'book_id' => $this->request->request('book_id'),
  967. ])->data;
  968. $paymentApplication = Factory::payment(Config::get('wechat'));
  969. $paymentApplication['cache'] = new RedisCache(Redis::instanceCache());
  970. $out_trade_no = date('YmdHis') . '_' . $userId . '_' . Random::build('alnum', 4);
  971. $productName = $goodsInfo['type'] == 2 ? '充值VIP' : '充值书币';
  972. $data = [
  973. 'funcode' => 'WP001',
  974. 'version' => '1.0.0',
  975. 'appId' => $payInfo['quartet_app_id'],
  976. 'mhtOrderNo' => $out_trade_no,
  977. 'mhtOrderType' => '01',
  978. 'mhtCurrencyType' => '156',
  979. 'mhtOrderAmt' => $goodsInfo['money'] * 100,
  980. 'mhtOrderStartTime' => date('YmdHis'),
  981. 'notifyUrl' => Config::get('site.scheme') . '://' . Api::PAY_CALLBACK_PREFIX . $payInfo['pay_host'] . '/api/wechat/ipaynowpay',
  982. 'frontNotifyUrl' => Config::get('site.scheme') . '://' . Api::PAY_CALLBACK_PREFIX . $payInfo['pay_host'] . '/api/wechat/ipaynowpay',
  983. 'mhtCharset' => 'UTF-8',
  984. 'deviceType' => '0600',
  985. 'payChannelType' => '13',
  986. 'outputType' => '1',
  987. 'mhtSubAppId' => $payInfo['appid'],
  988. 'consumerId' => Cookie::get('openid'),
  989. 'mhtLimitPay' => '0',
  990. 'mhtSignType' => 'MD5',
  991. ];
  992. $goodsDes = Config::get('site.goodsdes');
  993. if ($goodsDes) {
  994. $data['mhtOrderDetail'] = $productName . ' ' . $goodsDes;
  995. } else {
  996. $data['mhtOrderDetail'] = $productName;
  997. }
  998. if (!empty($adminConfig['json']['authorizer_info']['nick_name'])) {
  999. if (empty($goods_des)) {
  1000. $zfxx = $userId . '_' . $adminConfig['json']['authorizer_info']['nick_name'] . '_' . $productName;
  1001. } else {
  1002. $zfxx = $userId . '_' . $adminConfig['json']['authorizer_info']['nick_name'] . '_' . $productName . '_' . $goods_des;
  1003. }
  1004. } else {
  1005. if (empty($goods_des)) {
  1006. $zfxx = $userId . '_' . $productName;
  1007. } else {
  1008. $zfxx = $userId . '_' . $productName . '_' . $goods_des;
  1009. }
  1010. }
  1011. $data['mhtOrderName'] = mb_substr($zfxx, 0, 120, 'utf-8');
  1012. $privateKey = $payInfo['quartet_app_private_no'];
  1013. $data['mhtSignature'] = IpaynowPayService::instance($privateKey)->makeSign($data);
  1014. $orderInfo = [
  1015. 'goods_id' => $goodsId,
  1016. 'out_trade_no' => $out_trade_no,
  1017. 'admin_id' => $adminId,
  1018. 'user_id' => $userId,
  1019. ];
  1020. try {
  1021. $result = IpaynowPayService::instance($payInfo['quartet_app_key'])->payIpaynowApi($data, $payInfo,
  1022. $goodsInfo, $orderInfo);
  1023. } catch (Exception $e) {
  1024. $this->success($e->getMessage());
  1025. }
  1026. $tnStr = urldecode($result['tn']);
  1027. parse_str($tnStr, $aJson);
  1028. $aJson['appId'] = $aJson['wxAppId'];
  1029. $aJson['package'] = 'prepay_id=' . $aJson['prepay_id'];
  1030. unset($aJson['wxAppId']);
  1031. unset($aJson['prepay_id']);
  1032. $json = json_encode($aJson);
  1033. $this->_createOrderInfo(ApiConstants::PAYMENT_METHOD_IPAYNOW, $adminId,
  1034. $adminExtend,
  1035. $goodsInfo,
  1036. $goodsCategory,
  1037. 0,
  1038. $out_trade_no,
  1039. $goodsId,
  1040. $payInfo,
  1041. $channelId,
  1042. '',
  1043. $groupId,
  1044. $json,
  1045. $kl_admin_info,
  1046. $channelExtend
  1047. );
  1048. }
  1049. return ['json' => $json, 'out_trade_no' => $out_trade_no];
  1050. }
  1051. /**
  1052. * 取消微信充值
  1053. */
  1054. public function wechatCancel()
  1055. {
  1056. try {
  1057. $url = $this->request->request('url'); // 充值页的url
  1058. $goodsId = $this->request->request('goods_id'); // 商品id
  1059. $adminId = UserService::instance()->getAdminId()->data;
  1060. $channelId = UserService::instance()->getUserInfo()->channel_id;
  1061. //判断是否为代理商服务号
  1062. $groupids = Auth::instance()->getGroupIds($adminId);
  1063. $groupid = current($groupids);
  1064. if ($groupid == 4) {
  1065. $row = model('Admin_extend')->where(['admin_id' => $adminId])->find();
  1066. if ($row['distribute'] == 1) {
  1067. $channelId = $adminId;
  1068. }
  1069. if ($row['can_distribute'] == 1) {
  1070. $config_row = model('AdminConfig')->where(['admin_id' => $adminId])->find();
  1071. } else {
  1072. $config_row = model('AdminConfig')->where(['admin_id' => $row['create_by']])->find();
  1073. }
  1074. } else {
  1075. $config_row = model('AdminConfig')->where(['admin_id' => $adminId])->find();
  1076. }
  1077. $userId = Cookie::get('user_id'); // 用户ID
  1078. $user = model('User')->getUserInfo($userId);
  1079. $goods = model('Goods')->getGoodsInfoById($goodsId);
  1080. if ($goods && $user['is_subscribe'] == 1) { // 已关注
  1081. if ($goods['type'] == 1) { //书币充值
  1082. $msg = '亲,您的书币订单还未完成支付,现充值' . floatval($goods['money']) . '元可获' . ($goods['kandian'] + $goods['free_kandian']) . '书币,赶紧行动吧!';
  1083. } else { //vip充值
  1084. $msg = '亲,您的订单还未完成支付,现充值' . floatval($goods['money']) . '元,' . $goods['day'] . '天免费看,赶紧行动吧!';
  1085. }
  1086. $url = del_url_params($url, 'code');
  1087. //文字
  1088. $ext_arr = [
  1089. 'mark' => BigData::BIG_DATA_CANCEL_RECHARGE,
  1090. 'push_time' => time()
  1091. ];
  1092. $url .= '&ext=' . urlencode(json_encode($ext_arr));
  1093. LogService::info('[ DOT] [URL] [ WNZI ]' . $url);
  1094. $msg .= "\n\n" . '<a href="' . $url . '&goods_id=' . $goodsId . '">(立即充值)</a>';
  1095. if (ActiveShareService::instance()->checkChannel($channelId)) {
  1096. //转发分享赚书币
  1097. $msg .= "\n\n" . ActiveShareService::instance()->getPushReplyContent($channelId);
  1098. }
  1099. //防止消息队列重复入队
  1100. $redis = Redis::instance();
  1101. $payCancelKey = "O-C:{$userId}:{$goodsId}";
  1102. $status = $redis->exists($payCancelKey);
  1103. if (!$status) {
  1104. $activity = model("Activity")->get(100);
  1105. //入消息队列
  1106. $data['user_id'] = $user['id'];
  1107. $data['openid'] = $user['openid'];
  1108. $data['goods_id'] = $goodsId;
  1109. $data['channel_id'] = $channelId;
  1110. //是否新充值用户且活动有效
  1111. if ($user['is_pay'] == 0 && $activity['status'] == 1) {
  1112. //只发送一次图文消息
  1113. $ispay = $user['first_cancel_pay'] ?? UserConstants::USER_FIRST_CANCEL_NEVER;
  1114. if ($ispay == 2) {
  1115. //更新用户首冲标志位
  1116. // model('User')->setConnect($data['user_id'])
  1117. // ->where('id', $data['user_id'])
  1118. // ->update(['first_cancel_pay' => 1]);
  1119. UserService::instance()->update(['first_cancel_pay' => UserConstants::USER_FIRST_CANCEL_START], ['id'=>$data['user_id']]);
  1120. //图文消息
  1121. $activityinfo = model("ManageKey")->getOneByKey("firstpay");
  1122. $ext_arr = [
  1123. 'mark' => BigData::BIG_DATA_FIRST_RECHARGE,
  1124. 'push_time' => time()
  1125. ];
  1126. $msg2 = [];
  1127. $msg2['title'] = $activityinfo['content'];
  1128. $msg2['image'] = $activityinfo['image'];
  1129. $msg2['url'] = getCurrentDomain($channelId, '/s/100?user_id=' . $user['id'] . '&ext=' . json_encode($ext_arr));
  1130. LogService::info('[ DOT] [URL] [ TW ]' . $msg2['url']);
  1131. $msg2['description'] = '书币半价,仅限前100名';
  1132. $data['msg'] = $msg2;
  1133. //添加定时客服消息任务(首冲9.9)
  1134. if(!isset($config_row['block_ios_user_switch']) || (isset($config_row['block_ios_user_switch']) && $config_row['block_ios_user_switch'] == 0)){
  1135. if ($config_row['first_recharge_imgtext_post'] == 1) {
  1136. $minites = $config_row['order_unrecharge_post_time'];
  1137. MqUserPayCancelService::instance()->sendFirstCancel($data, $minites);
  1138. }
  1139. }else{
  1140. if(Ua::getOs() != 'iOS' && $config_row['first_recharge_imgtext_post'] == 1){
  1141. $minites = $config_row['order_unrecharge_post_time'];
  1142. MqUserPayCancelService::instance()->sendFirstCancel($data, $minites);
  1143. }
  1144. }
  1145. }
  1146. }
  1147. //redis标记设置
  1148. $expire = (intval(Config::get('site.user_cancel_pay_time')) * 60) + 60; //单位秒
  1149. $redis->setex($payCancelKey, $expire, 1);
  1150. $data['msg'] = $msg;
  1151. //添加定时客服消息任务(取消充值)
  1152. if(!isset($config_row['block_ios_user_switch']) || (isset($config_row['block_ios_user_switch']) && $config_row['block_ios_user_switch'] == 0)){
  1153. MqUserPayCancelService::instance()->sendNormalCancel($data);
  1154. }else{
  1155. if(Ua::getOs() != 'iOS'){
  1156. MqUserPayCancelService::instance()->sendNormalCancel($data);
  1157. }
  1158. }
  1159. }
  1160. }
  1161. } catch (Exception $exception) {
  1162. $this->error($exception->getMessage());
  1163. }
  1164. }
  1165. }