MiniProgramService.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace crmeb\services\app;
  12. use app\services\order\StoreOrderTakeServices;
  13. use crmeb\exceptions\AdminException;
  14. use crmeb\services\SystemConfigService;
  15. use app\services\pay\PayNotifyServices;
  16. use crmeb\services\easywechat\Application;
  17. use EasyWeChat\Payment\Order;
  18. use think\facade\Log;
  19. use crmeb\utils\Hook;
  20. use think\facade\Cache;
  21. use think\Response;
  22. /**
  23. * 微信小程序接口
  24. * Class WechatMinService
  25. * @package service
  26. */
  27. class MiniProgramService
  28. {
  29. const MSG_CODE = [
  30. '1' => '未创建直播间',
  31. '1003' => '商品id不存在',
  32. '47001' => '入参格式不符合规范',
  33. '200002' => '入参错误',
  34. '300001' => '禁止创建/更新商品 或 禁止编辑&更新房间',
  35. '300002' => '名称长度不符合规则',
  36. '300006' => '图片上传失败',
  37. '300022' => '此房间号不存在',
  38. '300023' => '房间状态 拦截',
  39. '300024' => '商品不存在',
  40. '300025' => '商品审核未通过',
  41. '300026' => '房间商品数量已经满额',
  42. '300027' => '导入商品失败',
  43. '300028' => '房间名称违规',
  44. '300029' => '主播昵称违规',
  45. '300030' => '主播微信号不合法',
  46. '300031' => '直播间封面图不合规',
  47. '300032' => '直播间分享图违规',
  48. '300033' => '添加商品超过直播间上限',
  49. '300034' => '主播微信昵称长度不符合要求',
  50. '300035' => '主播微信号不存在',
  51. '300036' => '主播微信号未实名认证',
  52. '300037' => '购物直播频道封面图不合规',
  53. '300038' => '未在小程序管理后台配置客服',
  54. '9410000' => '直播间列表为空',
  55. '9410001' => '获取房间失败',
  56. '9410002' => '获取商品失败',
  57. '9410003' => '获取回放失败',
  58. '300003' => '价格输入不合规',
  59. '300004' => '商品名称存在违规违法内容',
  60. '300005' => '商品图片存在违规违法内容',
  61. '300007' => '线上小程序版本不存在该链接',
  62. '300008' => '添加商品失败',
  63. '300009' => '商品审核撤回失败',
  64. '300010' => '商品审核状态不对',
  65. '300011' => '操作非法',
  66. '300012' => '没有提审额度',
  67. '300013' => '提审失败',
  68. '300014' => '审核中,无法删除',
  69. '300017' => '商品未提审',
  70. '300018' => '图片尺寸不符合要求',
  71. '300021' => '商品添加成功,审核失败',
  72. '40001' => 'AppSecret错误或者AppSecret不属于这个小程序,请确认AppSecret 的正确性',
  73. '40002' => '请确保grant_type字段值为client_credential',
  74. '40013' => '不合法的AppID,请检查AppID的正确性,避免异常字符,注意大小写',
  75. '40125' => '小程序配置无效,请检查配置',
  76. '41002' => '缺少appid参数',
  77. '41004' => '缺少secret参数',
  78. '43104' => 'appid与openid不匹配',
  79. '48001' => '微信接口暂无权限,请先去获取',
  80. '-1' => '系统错误',
  81. ];
  82. /**
  83. * @var Application
  84. */
  85. protected static $instance;
  86. /**
  87. * @return array
  88. */
  89. public static function options()
  90. {
  91. $wechat = SystemConfigService::more(['wechat_app_appsecret', 'wechat_app_appid', 'site_url', 'routine_appId', 'routine_appsecret']);
  92. $payment = SystemConfigService::more(['pay_weixin_mchid', 'pay_weixin_key', 'pay_weixin_client_cert', 'pay_weixin_client_key', 'pay_weixin_open', 'pay_new_weixin_open', 'pay_new_weixin_mchid']);
  93. $config = [];
  94. if (request()->isApp()) {
  95. $appId = isset($wechat['wechat_app_appid']) ? trim($wechat['wechat_app_appid']) : '';
  96. $appsecret = isset($wechat['wechat_app_appsecret']) ? trim($wechat['wechat_app_appsecret']) : '';
  97. } else {
  98. $appId = isset($wechat['routine_appId']) ? trim($wechat['routine_appId']) : '';
  99. $appsecret = isset($wechat['routine_appsecret']) ? trim($wechat['routine_appsecret']) : '';
  100. }
  101. $config = [
  102. 'token' => isset($wechat['wechat_token']) ? trim($wechat['wechat_token']) : '',
  103. 'aes_key' => isset($wechat['wechat_encodingaeskey']) ? trim($wechat['wechat_encodingaeskey']) : '',
  104. ];
  105. $config['mini_program'] = [
  106. 'app_id' => $appId,
  107. 'secret' => $appsecret,
  108. 'token' => isset($wechat['wechat_token']) ? trim($wechat['wechat_token']) : '',
  109. 'aes_key' => isset($wechat['wechat_encodingaeskey']) ? trim($wechat['wechat_encodingaeskey']) : ''
  110. ];
  111. $config['payment'] = [
  112. 'app_id' => $appId,
  113. 'merchant_id' => empty($payment['pay_new_weixin_open']) ? trim($payment['pay_weixin_mchid']) : trim($payment['pay_new_weixin_mchid']),
  114. 'key' => trim($payment['pay_weixin_key']),
  115. 'cert_path' => substr(public_path(parse_url($payment['pay_weixin_client_cert'])['path']), 0, strlen(public_path(parse_url($payment['pay_weixin_client_cert'])['path'])) - 1),
  116. 'key_path' => substr(public_path(parse_url($payment['pay_weixin_client_key'])['path']), 0, strlen(public_path(parse_url($payment['pay_weixin_client_key'])['path'])) - 1),
  117. 'notify_url' => trim($wechat['site_url']) . '/api/pay/notify/routine'
  118. ];
  119. return $config;
  120. }
  121. /**
  122. * 初始化
  123. * @param bool $cache
  124. * @return Application
  125. */
  126. public static function application($cache = false)
  127. {
  128. (self::$instance === null || $cache === true) && (self::$instance = new Application(self::options()));
  129. return self::$instance;
  130. }
  131. /**
  132. * 小程序接口
  133. * @return \EasyWeChat\MiniProgram\MiniProgram
  134. */
  135. public static function miniprogram()
  136. {
  137. return self::application()->mini_program;
  138. }
  139. /**
  140. * 获得用户信息 根据code 获取session_key
  141. * @param array|string $openid
  142. * @return $userInfo
  143. */
  144. public static function getUserInfo($code)
  145. {
  146. try {
  147. return self::miniprogram()->sns->getSessionKey($code);
  148. } catch (\Throwable $e) {
  149. throw new AdminException($e->getMessage());
  150. }
  151. }
  152. /**
  153. * 加密数据解密
  154. * @param $sessionKey
  155. * @param $iv
  156. * @param $encryptData
  157. * @return $userInfo
  158. */
  159. public static function encryptor($sessionKey, $iv, $encryptData)
  160. {
  161. return self::miniprogram()->encryptor->decryptData($sessionKey, $iv, $encryptData);
  162. }
  163. /**
  164. * 上传临时素材接口
  165. * @return \EasyWeChat\Material\Temporary
  166. */
  167. public static function materialTemporaryService()
  168. {
  169. return self::miniprogram()->material_temporary;
  170. }
  171. /**
  172. * 客服消息接口
  173. * @param null $to
  174. * @param null $message
  175. */
  176. public static function staffService()
  177. {
  178. return self::miniprogram()->staff;
  179. }
  180. /**
  181. * 微信小程序二维码生成接口
  182. * @return \EasyWeChat\QRCode\QRCode
  183. */
  184. public static function qrcodeService()
  185. {
  186. return self::miniprogram()->qrcode;
  187. }
  188. /**微信小程序二维码生成接口不限量永久
  189. * @param $scene
  190. * @param null $page
  191. * @param null $width
  192. * @param null $autoColor
  193. * @param array $lineColor
  194. * @return \Psr\Http\Message\StreamInterface
  195. */
  196. public static function appCodeUnlimitService($scene, $page = null, $width = 430, $autoColor = false, $lineColor = ['r' => 0, 'g' => 0, 'b' => 0])
  197. {
  198. return self::qrcodeService()->appCodeUnlimit($scene, $page, $width, $autoColor, $lineColor);
  199. }
  200. /**
  201. * 模板消息接口
  202. * @return \EasyWeChat\Notice\Notice
  203. */
  204. public static function noticeService()
  205. {
  206. return self::miniprogram()->notice;
  207. }
  208. /**
  209. * 订阅模板消息接口
  210. * @return \crmeb\services\subscribe\ProgramSubscribe
  211. */
  212. public static function SubscribenoticeService()
  213. {
  214. return self::miniprogram()->now_notice;
  215. }
  216. /**
  217. * 发送订阅消息
  218. * @param string $touser 接收者(用户)的 openid
  219. * @param string $templateId 所需下发的订阅模板id
  220. * @param array $data 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
  221. * @param string $link 击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
  222. * @return \EasyWeChat\Support\Collection|null
  223. * @throws \EasyWeChat\Core\Exceptions\HttpException
  224. * @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
  225. */
  226. public static function sendSubscribeTemlate(string $touser, string $templateId, array $data, string $link = '')
  227. {
  228. return self::SubscribenoticeService()->to($touser)->template($templateId)->andData($data)->withUrl($link)->send();
  229. }
  230. /**
  231. * 添加订阅消息模版
  232. * @param string $tid
  233. * @param array $kidList
  234. * @param string $sceneDesc
  235. * @return mixed
  236. */
  237. public static function addSubscribeTemplate(string $tid, array $kidList, string $sceneDesc = '')
  238. {
  239. try {
  240. $res = self::SubscribenoticeService()->addTemplate($tid, $kidList, $sceneDesc);
  241. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['priTmplId'])) {
  242. return $res['priTmplId'];
  243. } else {
  244. Log::error('添加订阅消息模版失败:' . $res['errmsg']);
  245. }
  246. } catch (\Throwable $e) {
  247. Log::error('添加订阅消息模版失败:' . $e->getMessage());
  248. }
  249. return true;
  250. }
  251. /**
  252. * 删除订阅消息模版
  253. * @param string $tid
  254. * @param array $kidList
  255. * @param string $sceneDesc
  256. * @return mixed
  257. */
  258. public static function delSubscribeTemplate(string $priTmplId)
  259. {
  260. try {
  261. $res = self::SubscribenoticeService()->delTemplate($priTmplId);
  262. if (isset($res['errcode']) && $res['errcode'] == 0) {
  263. return true;
  264. } else {
  265. Log::error('删除订阅消息模版失败:' . $res['errmsg']);
  266. }
  267. } catch (\Throwable $e) {
  268. Log::error('删除订阅消息模版失败:' . $e->getMessage());
  269. }
  270. return true;
  271. }
  272. /**
  273. * 获取模版标题的关键词列表
  274. * @param string $tid
  275. * @return mixed
  276. */
  277. public static function getSubscribeTemplateKeyWords(string $tid)
  278. {
  279. try {
  280. $res = self::SubscribenoticeService()->getPublicTemplateKeywords($tid);
  281. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['data'])) {
  282. return $res['data'];
  283. } else {
  284. throw new AdminException($res['errmsg']);
  285. }
  286. } catch (\Throwable $e) {
  287. throw new AdminException($e);
  288. }
  289. }
  290. /**
  291. * 获取订阅消息列表
  292. * @return mixed
  293. */
  294. public static function getSubscribeTemplateList()
  295. {
  296. try {
  297. return self::SubscribenoticeService()->getTemplateList();
  298. } catch (\Exception $e) {
  299. throw new AdminException($e->getMessage());
  300. }
  301. }
  302. /**
  303. * 支付
  304. * @return \EasyWeChat\Payment\Payment
  305. */
  306. public static function paymentService()
  307. {
  308. return self::application()->payment;
  309. }
  310. /**
  311. * 生成支付订单对象
  312. * @param $openid
  313. * @param $out_trade_no
  314. * @param $total_fee
  315. * @param $attach
  316. * @param $body
  317. * @param string $detail
  318. * @param string $trade_type
  319. * @param array $options
  320. * @return Order
  321. */
  322. protected static function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
  323. {
  324. $total_fee = bcmul($total_fee, 100, 0);
  325. $order = array_merge(compact('openid', 'out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options);
  326. if ($order['detail'] == '') unset($order['detail']);
  327. return new Order($order);
  328. }
  329. /**
  330. * 获得下单ID
  331. * @param $openid
  332. * @param $out_trade_no
  333. * @param $total_fee
  334. * @param $attach
  335. * @param $body
  336. * @param string $detail
  337. * @param string $trade_type
  338. * @param array $options
  339. * @return mixed
  340. */
  341. public static function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
  342. {
  343. $key = 'pay_' . $out_trade_no;
  344. $result = Cache::get($key);
  345. if ($result) {
  346. return $result;
  347. } else {
  348. $order = self::paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options);
  349. $result = self::paymentService()->prepare($order);
  350. if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
  351. Cache::set($key, $result->prepay_id, 7000);
  352. return $result->prepay_id;
  353. } else {
  354. if ($result->return_code == 'FAIL') {
  355. exception('微信支付错误返回:' . $result->return_msg);
  356. } else if (isset($result->err_code)) {
  357. exception('微信支付错误返回:' . $result->err_code_des);
  358. } else {
  359. exception('没有获取微信支付的预支付ID,请重新发起支付!');
  360. }
  361. exit;
  362. }
  363. }
  364. }
  365. /**
  366. * 获得下单ID
  367. * @param $openid
  368. * @param $out_trade_no
  369. * @param $total_fee
  370. * @param $attach
  371. * @param $body
  372. * @param string $detail
  373. * @param string $trade_type
  374. * @param array $options
  375. * @return mixed
  376. */
  377. public static function newPaymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $options = [])
  378. {
  379. $key = 'pay_' . $out_trade_no;
  380. $result = Cache::get($key);
  381. if ($result) {
  382. return $result;
  383. } else {
  384. $order = self::paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $options);
  385. $result = self::application()->minipay->createorder($order);
  386. if ($result->errcode === 0) {
  387. Cache::set($key, $result->payment_params, 7000);
  388. return $result->payment_params;
  389. } else {
  390. exception('微信支付错误返回:' . '[' . $result->errcode . ']' . $result->errmsg);
  391. exit;
  392. }
  393. }
  394. }
  395. /**
  396. * 获得jsSdk支付参数
  397. * @param $openid
  398. * @param $out_trade_no
  399. * @param $total_fee
  400. * @param $attach
  401. * @param $body
  402. * @param string $detail
  403. * @param string $trade_type
  404. * @param array $options
  405. * @return array|string
  406. */
  407. public static function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
  408. {
  409. return self::paymentService()->configForJSSDKPayment(self::paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options));
  410. }
  411. /**
  412. * 获得jsSdk支付参数
  413. * @param $openid
  414. * @param $out_trade_no
  415. * @param $total_fee
  416. * @param $attach
  417. * @param $body
  418. * @param string $detail
  419. * @param string $trade_type
  420. * @param array $options
  421. * @return array|string
  422. */
  423. public static function newJsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $options = [])
  424. {
  425. $config = self::newPaymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $options);
  426. $config['timestamp'] = $config['timeStamp'];
  427. unset($config['timeStamp']);
  428. return $config;
  429. }
  430. /**
  431. * 获得App支付参数
  432. * @param $openid
  433. * @param $out_trade_no
  434. * @param $total_fee
  435. * @param $attach
  436. * @param $body
  437. * @param string $detail
  438. * @param string $trade_type
  439. * @param array $options
  440. * @return array|string
  441. */
  442. public static function appPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = Order::APP, $options = [])
  443. {
  444. return self::paymentService()->configForAppPayment(self::paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options));
  445. }
  446. /**
  447. * 使用商户订单号退款
  448. * @param $orderNo
  449. * @param $refundNo
  450. * @param $totalFee
  451. * @param null $refundFee
  452. * @param null $opUserId
  453. * @param string $refundReason
  454. * @param string $type
  455. * @param string $refundAccount
  456. */
  457. public static function refund($orderNo, $refundNo, $totalFee, $refundFee = null, $opUserId = null, $refundReason = '', $type = 'out_trade_no', $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS')
  458. {
  459. $totalFee = floatval($totalFee);
  460. $refundFee = floatval($refundFee);
  461. if ($type == 'out_trade_no') {
  462. return self::paymentService()->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $type, $refundAccount, $refundReason);
  463. } else {
  464. return self::paymentService()->refundByTransactionId($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundAccount, $refundReason);
  465. }
  466. }
  467. /**
  468. * 使用商户订单号退款
  469. * @param $orderNo
  470. * @param $refundNo
  471. * @param $totalFee
  472. * @param null $refundFee
  473. * @param null $opUserId
  474. * @param string $refundReason
  475. * @param string $type
  476. * @param string $refundAccount
  477. */
  478. public static function miniRefund($orderNo, $totalFee, $refundFee = null, $opt)
  479. {
  480. $totalFee = floatval($totalFee);
  481. $refundFee = floatval($refundFee);
  482. $order = [
  483. 'openid' => $opt['open_id'],
  484. 'trade_no' => $opt['order_id'],
  485. 'transaction_id' => $opt['trade_no'],
  486. 'refund_no' => $opt['refund_no'],
  487. 'total_amount' => $totalFee,
  488. 'refund_amount' => $refundFee,
  489. ];
  490. return self::application()->minipay->refundorder($order);
  491. }
  492. /** 根据订单号退款
  493. * @param $orderNo
  494. * @param array $opt
  495. * @return bool
  496. */
  497. public static function payOrderRefund($orderNo, array $opt)
  498. {
  499. if (!isset($opt['pay_price'])) throw new AdminException(400730);
  500. if (sys_config('pay_weixin_client_key') == '' || sys_config('pay_weixin_client_cert') == '') throw new AdminException(400739);
  501. $totalFee = floatval(bcmul($opt['pay_price'], 100, 0));
  502. $refundFee = isset($opt['refund_price']) ? floatval(bcmul($opt['refund_price'], 100, 0)) : null;
  503. $refundReason = $opt['desc'] ?? '';
  504. $refundNo = $opt['refund_id'] ?? $orderNo;
  505. $opUserId = $opt['op_user_id'] ?? null;
  506. $type = $opt['type'] ?? 'out_trade_no';
  507. /*仅针对老资金流商户使用
  508. REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款)
  509. REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款*/
  510. $refundAccount = $opt['refund_account'] ?? 'REFUND_SOURCE_UNSETTLED_FUNDS';
  511. try {
  512. $res = (self::refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundReason, $type, $refundAccount));
  513. if ($res->return_code == 'FAIL') throw new AdminException(400731, ['msg' => $res->return_msg]);
  514. if (isset($res->err_code)) throw new AdminException(400731, ['msg' => $res->err_code_des]);
  515. } catch (\Exception $e) {
  516. throw new AdminException($e->getMessage());
  517. }
  518. return true;
  519. }
  520. /**
  521. * 微信支付成功回调接口
  522. * @return \Symfony\Component\HttpFoundation\Response
  523. * @throws \EasyWeChat\Core\Exceptions\FaultException
  524. */
  525. public static function handleNotify()
  526. {
  527. return self::paymentService()->handleNotify(function ($notify, $successful) {
  528. if ($successful && isset($notify->out_trade_no)) {
  529. if (isset($notify->attach) && $notify->attach) {
  530. if (($count = strpos($notify->out_trade_no, '_')) !== false) {
  531. $notify->out_trade_no = substr($notify->out_trade_no, $count + 1);
  532. }
  533. (new Hook(PayNotifyServices::class, 'wechat'))->listen($notify->attach, $notify->out_trade_no, $notify->transaction_id);
  534. }
  535. return false;
  536. }
  537. });
  538. }
  539. /**
  540. * 作为客服消息发送
  541. * @param $to
  542. * @param $message
  543. * @return bool
  544. */
  545. public static function staffTo($to, $message)
  546. {
  547. $staff = self::staffService();
  548. $staff = is_callable($message) ? $staff->message($message()) : $staff->message($message);
  549. $res = $staff->to($to)->send();
  550. return $res;
  551. }
  552. /**
  553. * 获取直播列表
  554. * @param int $page
  555. * @param int $limit
  556. * @return array
  557. */
  558. public static function getLiveInfo(int $page = 1, int $limit = 10)
  559. {
  560. try {
  561. $res = self::miniprogram()->wechat_live->getLiveInfo($page, $limit);
  562. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['room_info']) && $res['room_info']) {
  563. return $res['room_info'];
  564. } else {
  565. return [];
  566. }
  567. } catch (\Throwable $e) {
  568. return [];
  569. }
  570. }
  571. /**
  572. * 获取直播回放
  573. * @param int $room_id
  574. * @param int $page
  575. * @param int $limit
  576. * @return mixed
  577. */
  578. public static function getLivePlayback(int $room_id, int $page = 1, int $limit = 10)
  579. {
  580. try {
  581. $res = self::miniprogram()->wechat_live->getLivePlayback($room_id, $page, $limit);
  582. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['live_replay'])) {
  583. return $res['live_replay'];
  584. } else {
  585. throw new AdminException($res['errmsg']);
  586. }
  587. } catch (\Throwable $e) {
  588. throw new AdminException(self::getValidMessgae($e));
  589. }
  590. }
  591. /**
  592. * 创建直播间
  593. * @param array $data
  594. * @return mixed
  595. */
  596. public static function createLiveRoom(array $data)
  597. {
  598. try {
  599. $res = self::miniprogram()->wechat_live->createRoom($data);
  600. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['roomId'])) {
  601. unset($res['errcode']);
  602. return $res;
  603. } else {
  604. throw new AdminException($res['errmsg']);
  605. }
  606. } catch (\Throwable $e) {
  607. throw new AdminException(self::getValidMessgae($e));
  608. }
  609. }
  610. /**
  611. * 直播间添加商品
  612. * @param int $roomId
  613. * @param $ids
  614. * @return bool
  615. */
  616. public static function roomAddGoods(int $roomId, $ids)
  617. {
  618. try {
  619. $res = self::miniprogram()->wechat_live->roomAddGoods($roomId, $ids);
  620. if (isset($res['errcode']) && $res['errcode'] == 0) {
  621. return true;
  622. } else {
  623. throw new AdminException($res['errmsg']);
  624. }
  625. } catch (\Throwable $e) {
  626. throw new AdminException(self::getValidMessgae($e));
  627. }
  628. }
  629. /**
  630. * 获取商品列表
  631. * @param int $status
  632. * @param int $page
  633. * @param int $limit
  634. * @return mixed
  635. */
  636. public static function getGoodsList(int $status = 2, int $page = 1, int $limit = 10)
  637. {
  638. try {
  639. $res = self::miniprogram()->wechat_live->getGoodsList($status, $page, $limit);
  640. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['goods'])) {
  641. return $res['goods'];
  642. } else {
  643. throw new AdminException($res['errmsg']);
  644. }
  645. } catch (\Throwable $e) {
  646. throw new AdminException(self::getValidMessgae($e));
  647. }
  648. }
  649. /**
  650. * 获取商品详情
  651. * @param $goods_ids
  652. * @return mixed
  653. */
  654. public static function getGooodsInfo($goods_ids)
  655. {
  656. try {
  657. $res = self::miniprogram()->wechat_live->getGooodsInfo($goods_ids);
  658. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['goods'])) {
  659. return $res['goods'];
  660. } else {
  661. throw new AdminException($res['errmsg']);
  662. }
  663. } catch (\Throwable $e) {
  664. throw new AdminException(self::getValidMessgae($e));
  665. }
  666. }
  667. /**
  668. * 添加商品
  669. * @param string $coverImgUrl
  670. * @param string $name
  671. * @param int $priceType
  672. * @param string $url
  673. * @param $price
  674. * @param string $price2
  675. * @return mixed
  676. */
  677. public static function addGoods(string $coverImgUrl, string $name, int $priceType, string $url, $price, $price2 = '')
  678. {
  679. try {
  680. $res = self::miniprogram()->wechat_live->addGoods($coverImgUrl, $name, $priceType, $url, $price, $price2);
  681. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['goodsId'])) {
  682. unset($res['errcode']);
  683. return $res;
  684. } else {
  685. throw new AdminException($res['errmsg']);
  686. }
  687. } catch (\Throwable $e) {
  688. throw new AdminException(self::getValidMessgae($e));
  689. }
  690. }
  691. /**
  692. * 商品撤回审核
  693. * @param int $goodsId
  694. * @param $auditId
  695. * @return bool
  696. */
  697. public static function resetauditGoods(int $goodsId, $auditId)
  698. {
  699. try {
  700. $res = self::miniprogram()->wechat_live->resetauditGoods($goodsId, $auditId);
  701. if (isset($res['errcode']) && $res['errcode'] == 0) {
  702. return true;
  703. } else {
  704. throw new AdminException($res['errmsg']);
  705. }
  706. } catch (\Throwable $e) {
  707. throw new AdminException(self::getValidMessgae($e));
  708. }
  709. }
  710. /**
  711. * 商品重新提交审核
  712. * @param int $goodsId
  713. * @return mixed
  714. */
  715. public static function auditGoods(int $goodsId)
  716. {
  717. try {
  718. $res = self::miniprogram()->wechat_live->auditGoods($goodsId);
  719. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['auditId'])) {
  720. return $res['auditId'];
  721. } else {
  722. throw new AdminException($res['errmsg']);
  723. }
  724. } catch (\Throwable $e) {
  725. throw new AdminException(self::getValidMessgae($e));
  726. }
  727. }
  728. /**
  729. * 删除商品
  730. * @param int $goodsId
  731. * @return bool
  732. */
  733. public static function deleteGoods(int $goodsId)
  734. {
  735. try {
  736. $res = self::miniprogram()->wechat_live->deleteGoods($goodsId);
  737. if (isset($res['errcode']) && $res['errcode'] == 0) {
  738. return true;
  739. } else {
  740. throw new AdminException($res['errmsg']);
  741. }
  742. } catch (\Throwable $e) {
  743. throw new AdminException(self::getValidMessgae($e));
  744. }
  745. }
  746. /**
  747. * 更新商品
  748. * @param int $goodsId
  749. * @param string $coverImgUrl
  750. * @param string $name
  751. * @param int $priceType
  752. * @param string $url
  753. * @param $price
  754. * @param string $price2
  755. * @return bool
  756. */
  757. public static function updateGoods(int $goodsId, string $coverImgUrl, string $name, int $priceType, string $url, $price, $price2 = '')
  758. {
  759. try {
  760. $res = self::miniprogram()->wechat_live->updateGoods($goodsId, $coverImgUrl, $name, $priceType, $url, $price, $price2);
  761. if (isset($res['errcode']) && $res['errcode'] == 0) {
  762. return true;
  763. } else {
  764. throw new AdminException($res['errmsg']);
  765. }
  766. } catch (\Throwable $e) {
  767. throw new AdminException(self::getValidMessgae($e));
  768. }
  769. }
  770. /**
  771. * 更新商品
  772. * @param int $goodsId
  773. * @param string $coverImgUrl
  774. * @param string $name
  775. * @param int $priceType
  776. * @param string $url
  777. * @param $price
  778. * @param string $price2
  779. * @return bool
  780. */
  781. public static function getRoleList($role = 2, int $page = 0, int $limit = 30, $keyword = '')
  782. {
  783. try {
  784. $res = self::miniprogram()->wechat_live->getRoleList($role, $page, $limit, $keyword);
  785. if (isset($res['errcode']) && $res['errcode'] == 0 && isset($res['list'])) {
  786. return $res['list'];
  787. } else {
  788. throw new AdminException($res['errmsg']);
  789. }
  790. } catch (\Throwable $e) {
  791. throw new AdminException(self::getValidMessgae($e));
  792. }
  793. }
  794. public static function getValidMessgae(\Throwable $e)
  795. {
  796. $message = '';
  797. if (!isset(self::MSG_CODE[$e->getCode()]) && strstr($e->getMessage(), 'Request AccessToken fail') !== false) {
  798. $message = str_replace('Request AccessToken fail. response:', '', $e->getMessage());
  799. $message = json_decode($message, true) ?: [];
  800. $errcode = $message['errcode'] ?? false;
  801. if ($errcode) {
  802. $message = self::MSG_CODE[$errcode] ?? $message;
  803. }
  804. }
  805. return $message ?: self::MSG_CODE[$e->getCode()] ?? $e->getMessage();
  806. }
  807. /**
  808. * @return Response
  809. * @throws \EasyWeChat\Server\BadRequestException
  810. */
  811. public static function serve(): Response
  812. {
  813. $wechat = self::application(true);
  814. $server = $wechat->server;
  815. self::hook($server);
  816. $response = $server->serve();
  817. return response($response->getContent());
  818. }
  819. private static function hook($server)
  820. {
  821. $server->setMessageHandler(function ($message) {
  822. switch ($message->MsgType) {
  823. case 'event':
  824. switch (strtolower($message->Event)) {
  825. case 'trade_manage_remind_access_api': // 小程序完成账期授权时 小程序产生第一笔交易时 已产生交易但从未发货的小程序,每天一次
  826. break;
  827. case 'trade_manage_remind_shipping': // 曾经发过货的小程序,订单超过48小时未发货时
  828. break;
  829. case 'trade_manage_order_settlement': // 订单完成发货时 订单结算时
  830. if (isset($message['estimated_settlement_time'])) { //订单完成发货时
  831. }
  832. if (isset($message['confirm_receive_method'])) { // 订单结算时
  833. /** @var StoreOrderTakeServices $StoreOrderTakeServices */
  834. $storeOrderTakeServices = app()->make(StoreOrderTakeServices::class);
  835. $storeOrderTakeServices->takeOrder($message['merchant_trade_no'], 0);
  836. }
  837. break;
  838. };
  839. break;
  840. };
  841. });
  842. }
  843. }