MiniProgramService.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <?php
  2. namespace library\services;
  3. use EasyWeChat\Foundation\Application;
  4. use think\facade\Route as Url;
  5. /**微信小程序接口
  6. * Class WechatMinService
  7. * @package service
  8. */
  9. class MiniProgramService
  10. {
  11. private static $instance = null;
  12. public function register($config)
  13. {
  14. return ['mini_program', new self()];
  15. }
  16. public static function options()
  17. {
  18. $config = [];
  19. $config['mini_program'] = [
  20. 'app_id' => 'wxb4c2433f398a6a48',
  21. 'secret' => '3fb376e8197f3fb9670644adbcabae59',
  22. 'token' => '',
  23. 'aes_key' => ''
  24. ];
  25. return $config;
  26. }
  27. public static function application($cache = false)
  28. {
  29. (self::$instance === null || $cache === true) && (self::$instance = new Application(self::options()));
  30. return self::$instance;
  31. }
  32. /**
  33. * 小程序接口
  34. * @return \EasyWeChat\MiniProgram\MiniProgram
  35. */
  36. public static function miniprogram()
  37. {
  38. return self::application()->mini_program;
  39. }
  40. /**
  41. * 获得用户信息 根据code 获取session_key
  42. * @param array|string $openid
  43. * @return $userInfo
  44. */
  45. public static function getUserInfo($code)
  46. {
  47. $userInfo = self::miniprogram()->sns->getSessionKey($code);
  48. return $userInfo;
  49. }
  50. /**
  51. * 加密数据解密
  52. * @param $sessionKey
  53. * @param $iv
  54. * @param $encryptData
  55. * @return $userInfo
  56. */
  57. public static function encryptor($sessionKey, $iv, $encryptData)
  58. {
  59. return self::miniprogram()->encryptor->decryptData($sessionKey, $iv, $encryptData);
  60. }
  61. /**
  62. * 上传临时素材接口
  63. * @return \EasyWeChat\Material\Temporary
  64. */
  65. public static function materialTemporaryService()
  66. {
  67. return self::miniprogram()->material_temporary;
  68. }
  69. /**
  70. * 客服消息接口
  71. * @param null $to
  72. * @param null $message
  73. */
  74. public static function staffService()
  75. {
  76. return self::miniprogram()->staff;
  77. }
  78. /**
  79. * 微信小程序二维码生成接口
  80. * @return \EasyWeChat\QRCode\QRCode
  81. */
  82. public static function qrcodeService()
  83. {
  84. return self::miniprogram()->qrcode;
  85. }
  86. /**微信小程序二维码生成接口不限量永久
  87. * @param $scene
  88. * @param null $page
  89. * @param null $width
  90. * @param null $autoColor
  91. * @param array $lineColor
  92. * @return \Psr\Http\Message\StreamInterface
  93. */
  94. public static function appCodeUnlimitService($scene, $page = null, $width = 430, $autoColor = false, $lineColor = ['r' => 0, 'g' => 0, 'b' => 0])
  95. {
  96. return self::qrcodeService()->appCodeUnlimit($scene, $page, $width, $autoColor, $lineColor);
  97. }
  98. /**
  99. * 模板消息接口
  100. * @return \EasyWeChat\Notice\Notice
  101. */
  102. public static function noticeService()
  103. {
  104. return self::miniprogram()->notice;
  105. }
  106. /**
  107. * 订阅模板消息接口
  108. * @return \crmeb\services\subscribe\ProgramSubscribe
  109. */
  110. public static function SubscribenoticeService()
  111. {
  112. return self::miniprogram()->now_notice;
  113. }
  114. /**
  115. * 发送订阅消息
  116. * @param string $touser 接收者(用户)的 openid
  117. * @param string $templateId 所需下发的订阅模板id
  118. * @param array $data 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
  119. * @param string $link 击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
  120. * @return \EasyWeChat\Support\Collection|null
  121. * @throws \EasyWeChat\Core\Exceptions\HttpException
  122. * @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
  123. */
  124. public static function sendSubscribeTemlate(string $touser, string $templateId, array $data, string $link = '')
  125. {
  126. return self::SubscribenoticeService()->to($touser)->template($templateId)->andData($data)->withUrl($link)->send();
  127. }
  128. /**
  129. * 支付
  130. * @return \EasyWeChat\Payment\Payment
  131. */
  132. public static function paymentService()
  133. {
  134. return self::application()->payment;
  135. }
  136. /**
  137. * 生成支付订单对象
  138. * @param $openid
  139. * @param $out_trade_no
  140. * @param $total_fee
  141. * @param $attach
  142. * @param $body
  143. * @param string $detail
  144. * @param string $trade_type
  145. * @param array $options
  146. * @return Order
  147. */
  148. protected static function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
  149. {
  150. $total_fee = bcmul($total_fee, 100, 0);
  151. $order = array_merge(compact('openid', 'out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options);
  152. if ($order['detail'] == '') unset($order['detail']);
  153. return new Order($order);
  154. }
  155. /**
  156. * 获得下单ID
  157. * @param $openid
  158. * @param $out_trade_no
  159. * @param $total_fee
  160. * @param $attach
  161. * @param $body
  162. * @param string $detail
  163. * @param string $trade_type
  164. * @param array $options
  165. * @return mixed
  166. */
  167. public static function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
  168. {
  169. $order = self::paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options);
  170. $result = self::paymentService()->prepare($order);
  171. if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
  172. try {
  173. PaymentRepositories::wechatPaymentPrepareProgram($order, $result->prepay_id);
  174. } catch (\Exception $e) {
  175. }
  176. return $result->prepay_id;
  177. } else {
  178. if ($result->return_code == 'FAIL') {
  179. exception('微信支付错误返回:' . $result->return_msg);
  180. } else if (isset($result->err_code)) {
  181. exception('微信支付错误返回:' . $result->err_code_des);
  182. } else {
  183. exception('没有获取微信支付的预支付ID,请重新发起支付!');
  184. }
  185. exit;
  186. }
  187. }
  188. /**
  189. * 获得jsSdk支付参数
  190. * @param $openid
  191. * @param $out_trade_no
  192. * @param $total_fee
  193. * @param $attach
  194. * @param $body
  195. * @param string $detail
  196. * @param string $trade_type
  197. * @param array $options
  198. * @return array|string
  199. */
  200. public static function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
  201. {
  202. return self::paymentService()->configForJSSDKPayment(self::paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options));
  203. }
  204. /**
  205. * 使用商户订单号退款
  206. * @param $orderNo
  207. * @param $refundNo
  208. * @param $totalFee
  209. * @param null $refundFee
  210. * @param null $opUserId
  211. * @param string $refundReason
  212. * @param string $type
  213. * @param string $refundAccount
  214. */
  215. public static function refund($orderNo, $refundNo, $totalFee, $refundFee = null, $opUserId = null, $refundReason = '', $type = 'out_trade_no', $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS')
  216. {
  217. $totalFee = floatval($totalFee);
  218. $refundFee = floatval($refundFee);
  219. return self::paymentService()->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason);
  220. }
  221. /** 根据订单号退款
  222. * @param $orderNo
  223. * @param array $opt
  224. * @return bool
  225. */
  226. public static function payOrderRefund($orderNo, array $opt)
  227. {
  228. if (!isset($opt['pay_price'])) throw new AdminException('缺少pay_price');
  229. $totalFee = floatval(bcmul($opt['pay_price'], 100, 0));
  230. $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'], 100, 0)) : null;
  231. $refundReason = isset($opt['desc']) ? $opt['desc'] : '';
  232. $refundNo = isset($opt['refund_id']) ? $opt['refund_id'] : $orderNo;
  233. $opUserId = isset($opt['op_user_id']) ? $opt['op_user_id'] : null;
  234. $type = isset($opt['type']) ? $opt['type'] : 'out_trade_no';
  235. /*仅针对老资金流商户使用
  236. REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款)
  237. REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款*/
  238. $refundAccount = isset($opt['refund_account']) ? $opt['refund_account'] : 'REFUND_SOURCE_UNSETTLED_FUNDS';
  239. try {
  240. $res = (self::refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundReason, $type, $refundAccount));
  241. if ($res->return_code == 'FAIL') throw new AdminException('退款失败:' . $res->return_msg);
  242. if (isset($res->err_code)) throw new AdminException('退款失败:' . $res->err_code_des);
  243. } catch (\Exception $e) {
  244. throw new AdminException($e->getMessage());
  245. }
  246. return true;
  247. }
  248. /**
  249. * 微信支付成功回调接口
  250. */
  251. public static function handleNotify()
  252. {
  253. self::paymentService()->handleNotify(function ($notify, $successful) {
  254. if ($successful && isset($notify->out_trade_no)) {
  255. if (isset($notify->attach) && $notify->attach) {
  256. if (($count = strpos($notify->out_trade_no, '_')) !== false) {
  257. $notify->out_trade_no = substr($notify->out_trade_no, $count + 1);
  258. }
  259. (new Hook(PaymentRepositories::class, 'wechat'))->listen($notify->attach, $notify->out_trade_no);
  260. }
  261. return false;
  262. }
  263. });
  264. }
  265. /**
  266. * 作为客服消息发送
  267. * @param $to
  268. * @param $message
  269. * @return bool
  270. */
  271. public static function staffTo($to, $message)
  272. {
  273. $staff = self::staffService();
  274. $staff = is_callable($message) ? $staff->message($message()) : $staff->message($message);
  275. $res = $staff->to($to)->send();
  276. return $res;
  277. }
  278. /**
  279. * 获取直播列表
  280. * @param int $page
  281. * @param int $limit
  282. * @return array
  283. */
  284. public static function getLiveInfo(int $page = 1, $limit = 10)
  285. {
  286. try {
  287. $res = self::miniprogram()->wechat_live->getLiveInfo($page, $limit);
  288. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['room_info']) && $res['room_info']) {
  289. return $res['room_info'];
  290. } else {
  291. return [];
  292. }
  293. } catch (\Throwable $e) {
  294. return [];
  295. }
  296. }
  297. }