MiniProgramService.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. namespace liuniu;
  3. use app\admin\model\Company;
  4. use app\common\model\WechatContext;
  5. use EasyWeChat\Factory;
  6. use think\Hook;
  7. use think\Request;
  8. class MiniProgramService
  9. {
  10. private static $instance = null;
  11. private static $app = null;
  12. public static function options($cid)
  13. {
  14. $info = Company::where('id',$cid)->find();
  15. $config = [
  16. 'app_id' => isset($info['routine_appid']) ? trim($info['routine_appid']) : '',
  17. 'secret' => isset($info['routine_appsecret']) ? trim($info['routine_appsecret']) : '',
  18. 'token' => isset($info['wechat_token']) ? trim($info['wechat_token']) : '',
  19. 'aes_key' => isset($info['wechat_encodingaeskey']) ? trim($info['wechat_encodingaeskey']) : ''
  20. ];
  21. if (isset($info['pay_routine_open']) && $info['pay_routine_open'] == 1) {
  22. $config1 = [
  23. 'merchant_id' => trim($info['pay_routine_mchid']),
  24. 'key' => trim($info['pay_routine_key']),
  25. 'cert_path' => realpath('.' . $info['pay_routine_client_cert']),
  26. 'key_path' => realpath('.' . $info['pay_routine_client_key']),
  27. 'notify_url' => Request::instance()->domain(). "/api/routine/notify/".$cid
  28. ];
  29. $config = array_merge($config,$config1);
  30. }
  31. @file_put_contents("mini_config.txt",$config);
  32. return $config;
  33. }
  34. public static function miniprogram($cache = false,$cid)
  35. {
  36. (self::$instance['cid'] === null || $cache === true) && (self::$instance['cid'] = Factory::miniProgram(self::options($cid)));
  37. return self::$instance['cid'];
  38. }
  39. /**
  40. * 支付接口
  41. * @param false $cache
  42. * @param int $cid
  43. * @return \EasyWeChat\Payment\Application|mixed
  44. */
  45. public static function payment($cache = false,$cid=0)
  46. {
  47. (self::$app[$cid] === null || $cache === true) && (self::$app[$cid] = Factory::payment(self::options($cid)));
  48. return self::$app[$cid];
  49. }
  50. /**
  51. * 获得用户信息 根据code 获取session_key
  52. * @param array|string $openid
  53. * @return $userInfo
  54. */
  55. public static function getUserInfo($cid,$code)
  56. {
  57. $userInfo = self::miniprogram(false,$cid)->auth->session($code);
  58. return $userInfo;
  59. }
  60. /**
  61. * 加密数据解密
  62. * @param $sessionKey
  63. * @param $iv
  64. * @param $encryptData
  65. * @return $userInfo
  66. */
  67. public static function encryptor($cid,$sessionKey, $iv, $encryptData)
  68. {
  69. return self::miniprogram(false,$cid)->encryptor->decryptData($sessionKey, $iv, $encryptData);
  70. }
  71. /**
  72. * 订阅模板消息接口
  73. * @return \crmeb\services\subscribe\ProgramSubscribe
  74. */
  75. public static function SubscribenoticeService($cid)
  76. {
  77. return self::miniprogram(false,$cid)->subscribe_message;
  78. }
  79. /**
  80. * 发送订阅消息
  81. * @param string $touser 接收者(用户)的 openid
  82. * @param string $templateId 所需下发的订阅模板id
  83. * @param array $data 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
  84. * @param string $link 击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
  85. * @return \EasyWeChat\Support\Collection|null
  86. * @throws \EasyWeChat\Core\Exceptions\HttpException
  87. * @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
  88. */
  89. public static function sendSubscribeTemlate($cid,string $touser, string $templateId, array $data, string $link = '')
  90. {
  91. $msg = [
  92. 'template_id' => $templateId, // 所需下发的订阅模板id
  93. 'touser' => $touser, // 接收者(用户)的 openid
  94. 'page' => $link, // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
  95. 'data' => $data,
  96. ];
  97. return self::SubscribenoticeService($cid)->send($msg);
  98. }
  99. /**
  100. * 生成支付订单对象
  101. * @param $openid
  102. * @param $out_trade_no
  103. * @param $total_fee
  104. * @param $attach
  105. * @param $body
  106. * @param string $detail
  107. * @param string $trade_type
  108. * @param array $options
  109. * @return Order
  110. */
  111. public static function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [],$cid=0)
  112. {
  113. $total_fee = bcmul($total_fee, 100, 0);
  114. $order = array_merge(compact('out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options);
  115. if (!is_null($openid)) $order['openid'] = $openid;
  116. if ($order['detail'] == '') unset($order['detail']);
  117. $result = self::payment(false,$cid)->order->unify($order);
  118. return $result;
  119. }
  120. /**
  121. * 使用商户订单号退款
  122. * @param $orderNo
  123. * @param $opt
  124. */
  125. public static function payOrderRefund($cid,$orderNo, array $opt)
  126. {
  127. if (!isset($opt['pay_price'])) exception('缺少pay_price');
  128. $totalFee = floatval(bcmul($opt['pay_price'], 100, 0));
  129. $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'], 100, 0)) : null;
  130. $refundReason = isset($opt['desc']) ? $opt['desc'] : '';
  131. $refundNo = isset($opt['refund_id']) ? $opt['refund_id'] : $orderNo;
  132. $opUserId = isset($opt['op_user_id']) ? $opt['op_user_id'] : null;
  133. $type = isset($opt['type']) ? $opt['type'] : 'out_trade_no';
  134. /*仅针对老资金流商户使用
  135. REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款)
  136. REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款*/
  137. $refundAccount = isset($opt['refund_account']) ? $opt['refund_account'] : 'REFUND_SOURCE_UNSETTLED_FUNDS';
  138. try {
  139. $res = self::payment('false',$cid)->byOutTradeNumber($orderNo,$refundNo,$totalFee,$refundFee,['refund_desc'=>$refundReason]);
  140. if ($res->return_code == 'FAIL') exception('退款失败:' . $res->return_msg);
  141. if (isset($res->err_code)) exception('退款失败:' . $res->err_code_des);
  142. } catch (\Exception $e) {
  143. exception($e->getMessage());
  144. }
  145. return true;
  146. }
  147. /**
  148. * 微信支付成功回调接口
  149. */
  150. public static function handleNotify($cid)
  151. {
  152. $response = self::payment(true,$cid)->handlePaidNotify(function ($notify, $successful) use($cid){
  153. if ($successful && isset($notify['out_trade_no'])) {
  154. if (isset($notify['attach']) && $notify['attach']) {
  155. if (($count = strpos($notify['out_trade_no'], '_')) !== false) {
  156. $notify['out_trade_no'] = substr($notify['out_trade_no'], $count + 1);
  157. }
  158. $params = [$cid,$notify['out_trade_no']];
  159. Hook::exec("\\liuniu\\repositories\\PaymentRepositories","wechat".ucfirst($notify['attach']),$params);
  160. }
  161. $data = ['eventkey' => 'notify', 'command' => '', 'refreshtime' => time(), 'openid' => $notify['openid'],'message'=>json_encode($notify)];
  162. $wechatContext = WechatContext::create($data, true);
  163. return true;
  164. }
  165. });
  166. $response->send();
  167. }
  168. public static function getToken($cid)
  169. {
  170. $token = self::miniprogram(false,$cid)->access_token->getToken();
  171. return $token;
  172. }
  173. }