MiniProgramService.php 8.4 KB

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