YunxinSmsService.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. <?php
  2. namespace ln\services;
  3. use app\common\dao\system\sms\SmsRecordDao;
  4. use app\common\repositories\store\broadcast\BroadcastRoomRepository;
  5. use app\common\repositories\store\order\StoreGroupOrderRepository;
  6. use app\common\repositories\store\order\StoreOrderRepository;
  7. use app\common\repositories\store\order\StoreRefundOrderRepository;
  8. use app\common\repositories\store\product\ProductRepository;
  9. use app\common\repositories\store\product\ProductTakeRepository;
  10. use app\common\repositories\store\service\StoreServiceRepository;
  11. use app\common\repositories\system\config\ConfigValueRepository;
  12. use ln\exceptions\SmsException;
  13. use FormBuilder\Exception\FormBuilderException;
  14. use FormBuilder\Factory\Elm;
  15. use FormBuilder\Form;
  16. use think\exception\ValidateException;
  17. use think\facade\Cache;
  18. use think\facade\Config;
  19. use think\facade\Route;
  20. /**
  21. * Class YunxinSmsService
  22. * @package ln\services
  23. * @author xaboy
  24. * @day 2020-05-18
  25. */
  26. class YunxinSmsService
  27. {
  28. /**
  29. * api
  30. */
  31. const API = 'https://sms.crmeb.net/api/';
  32. // const API = 'http://plat.crmeb.net/api/';
  33. /**
  34. * @var array
  35. */
  36. protected $config;
  37. /**
  38. * YunxinSmsService constructor.
  39. * @param array $config
  40. */
  41. public function __construct(array $config = [])
  42. {
  43. $this->config = $config;
  44. if (isset($this->config['sms_token'])) {
  45. $this->config['sms_token'] = $this->getToken();
  46. }
  47. }
  48. public static function sendMessage($tempId, $id)
  49. {
  50. if ($tempId == 'DELIVER_GOODS_CODE') {
  51. if (!systemConfig('sms_fahuo_status')) return;
  52. $order = app()->make(StoreOrderRepository::class)->get($id);
  53. if (!$order || !$order->user_phone) return;
  54. $nickname = $order->user->nickname;
  55. $store_name = $order->orderProduct[0]['cart_info']['product']['store_name'] . (count($order->orderProduct) ? '等' : '');
  56. $order_id = $order->order_sn;
  57. self::create()->send($order->user_phone, $tempId, compact('nickname', 'store_name', 'order_id'));
  58. } else if ($tempId == 'TAKE_DELIVERY_CODE') {
  59. if (!systemConfig('sms_take_status')) return;
  60. $order = app()->make(StoreOrderRepository::class)->get($id);
  61. if (!$order || !$order->user_phone) return;
  62. $order_id = $order->order_sn;
  63. $store_name = $order->orderProduct[0]['cart_info']['product']['store_name'] . (count($order->orderProduct) ? '等' : '');
  64. self::create()->send($order->user_phone, $tempId, compact('store_name', 'order_id'));
  65. } else if ($tempId == 'PAY_SUCCESS_CODE') {
  66. if (!systemConfig('sms_pay_status')) return;
  67. $order = app()->make(StoreGroupOrderRepository::class)->get($id);
  68. if (!$order || !$order->user_phone) return;
  69. $pay_price = $order->pay_price;
  70. $order_id = $order->group_order_sn;
  71. self::create()->send($order->user_phone, $tempId, compact('pay_price', 'order_id'));
  72. } else if ($tempId == 'PRICE_REVISION_CODE') {
  73. if (!systemConfig('sms_revision_status')) return;
  74. $order = app()->make(StoreOrderRepository::class)->get($id);
  75. if (!$order || !$order->user_phone) return;
  76. $pay_price = $order->pay_price;
  77. $order_id = $order->order_sn;
  78. self::create()->send($order->user_phone, $tempId, compact('pay_price', 'order_id'));
  79. } else if ($tempId == 'ORDER_PAY_FALSE') {
  80. if (!systemConfig('sms_pay_false_status')) return;
  81. $order = app()->make(StoreGroupOrderRepository::class)->get($id);
  82. if (!$order || !$order->user_phone) return;
  83. $order_id = $order->group_order_sn;
  84. self::create()->send($order->user_phone, $tempId, compact('order_id'));
  85. } else if ($tempId == 'REFUND_FAIL_CODE') {
  86. if (!systemConfig('sms_refund_fail_status')) return;
  87. $order = app()->make(StoreRefundOrderRepository::class)->get($id);
  88. if (!$order || !$order->order->user_phone) return;
  89. $order_id = $order->order->order_sn;
  90. $store_name = $order->refundProduct[0]->product['cart_info']['product']['store_name'] . (count($order->refundProduct) ? '等' : '');
  91. self::create()->send($order->order->user_phone, $tempId, compact('order_id', 'store_name'));
  92. } else if ($tempId == 'REFUND_SUCCESS_CODE') {
  93. if (!systemConfig('sms_refund_success_status')) return;
  94. $order = app()->make(StoreRefundOrderRepository::class)->get($id);
  95. if (!$order || !$order->order->user_phone) return;
  96. $order_id = $order->order->order_sn;
  97. $store_name = $order->refundProduct[0]->product['cart_info']['product']['store_name'] . (count($order->refundProduct) ? '等' : '');
  98. self::create()->send($order->order->user_phone, $tempId, compact('order_id', 'store_name'));
  99. } else if ($tempId == 'REFUND_CONFORM_CODE') {
  100. if (!systemConfig('sms_refund_confirm_status')) return;
  101. $order = app()->make(StoreRefundOrderRepository::class)->get($id);
  102. if (!$order || !$order->order->user_phone) return;
  103. $order_id = $order->order->order_sn;
  104. $store_name = $order->refundProduct[0]->product['cart_info']['product']['store_name'] . (count($order->refundProduct) ? '等' : '');
  105. self::create()->send($order->order->user_phone, $tempId, compact('order_id', 'store_name'));
  106. } else if ($tempId == 'ADMIN_PAY_SUCCESS_CODE') {
  107. if (!systemConfig('sms_admin_pay_status')) return;
  108. $order = app()->make(StoreGroupOrderRepository::class)->get($id);
  109. if (!$order) return;
  110. foreach ($order->orderList as $_order) {
  111. self::sendMerMessage($_order->mer_id, $tempId, [
  112. 'order_id' => $_order->order_sn
  113. ]);
  114. }
  115. } else if ($tempId == 'ADMIN_RETURN_GOODS_CODE') {
  116. if (!systemConfig('sms_admin_return_status')) return;
  117. $order = app()->make(StoreRefundOrderRepository::class)->get($id);
  118. if (!$order) return;
  119. self::sendMerMessage($order->mer_id, $tempId, [
  120. 'order_id' => $order->refund_order_sn
  121. ]);
  122. } else if ($tempId == 'ADMIN_TAKE_DELIVERY_CODE') {
  123. if (!systemConfig('sms_admin_take_status')) return;
  124. $order = app()->make(StoreOrderRepository::class)->get($id);
  125. if (!$order) return;
  126. self::sendMerMessage($order->mer_id, $tempId, [
  127. 'order_id' => $order->order_sn
  128. ]);
  129. } else if ($tempId == 'ADMIN_DELIVERY_CODE') {
  130. if (!systemConfig('sms_admin_postage_status')) return;
  131. $order = app()->make(StoreOrderRepository::class)->get($id);
  132. if (!$order) return;
  133. self::sendMerMessage($order->mer_id, $tempId, [
  134. 'order_id' => $order->order_sn
  135. ]);
  136. } else if ($tempId == 'BROADCAST_ROOM_CODE') {
  137. if (!systemConfig('sms_broadcast_room_status')) return;
  138. $room = app()->make(BroadcastRoomRepository::class)->get($id);
  139. if (!$room) return;
  140. self::create()->send($room->phone, $tempId, [
  141. 'wechat' => $room->anchor_wechat,
  142. 'date' => date('Y年m月d日 H时i分', strtotime($room->start_time))
  143. ]);
  144. } else if ($tempId == 'BROADCAST_ROOM_FAIL') {
  145. if (!systemConfig('sms_broadcast_room_fail')) return;
  146. $room = app()->make(BroadcastRoomRepository::class)->get($id);
  147. if (!$room) return;
  148. self::create()->send($room->phone, $tempId, [
  149. 'wechat' => $room->anchor_wechat
  150. ]);
  151. } else if ($tempId == 'PAY_PRESELL_CODE') {
  152. if (!systemConfig('sms_pay_presell_status')) return;
  153. $order = app()->make(StoreOrderRepository::class)->get($id);
  154. if (!$order || !$order->user_phone) return;
  155. self::create()->send($order->user_phone, $tempId, [
  156. 'date' => date('Y-m-d', strtotime($order->pay_time)),
  157. 'product_name' => $order->orderProduct[0]['cart_info']['product']['store_name'] ?? ''
  158. ]);
  159. } else if ($tempId == 'APPLY_MER_SUCCESS') {
  160. if (systemConfig('sms_apply_mer_succ_status') !== '' && !systemConfig('sms_apply_mer_succ_status')) return;
  161. self::create()->send($id['phone'], $tempId, [
  162. 'date' => date('m月d日', strtotime($id['date'])),
  163. 'mer' => $id['mer'],
  164. 'phone' => $id['phone'],
  165. 'pwd' => $id['pwd'],
  166. 'site_name' => systemConfig('site_name'),
  167. ]);
  168. } else if ($tempId == 'APPLY_MER_FAIL') {
  169. if (systemConfig('sms_apply_mer_fail_status') !== '' && !systemConfig('sms_apply_mer_fail_status')) return;
  170. self::create()->send($id['phone'], $tempId, [
  171. 'date' => date('m月d日', strtotime($id['date'])),
  172. 'mer' => $id['mer'],
  173. 'site' => systemConfig('site_name'),
  174. ]);
  175. } else if ($tempId == 'ARRIVAL_CODE') {
  176. if (!systemConfig('procudt_increase_sms')) return;
  177. $product = app()->make(ProductRepository::class)->getWhere(['product_id' => $id],'*',['attrValue']);
  178. if(!$product) return false;
  179. $unique[] = 1;
  180. foreach ($product['attrValue'] as $item) {
  181. if($item['stock'] > 0){
  182. $unique[] = $item['unique'];
  183. }
  184. }
  185. $make = app()->make(ProductTakeRepository::class);
  186. $query = $make->getSearch(['product_id' => $id,'status' =>0,'type' => 1])->where('unique','in',$unique);
  187. $tak_id = $query->column('product_take_id');
  188. $ret = $query->with(['user'])->select();
  189. app()->make(ProductTakeRepository::class)->updates($tak_id,['status' => 1]);
  190. foreach ($ret as $item){
  191. if($item->user->phone){
  192. self::create()->send($item->user->phone, $tempId, [
  193. 'product' => $product->store_name,
  194. 'site' => systemConfig('site_name'),
  195. ]);
  196. }
  197. }
  198. } else if ($tempId == 'INTEGRAL_INVALID') {
  199. if (!systemConfig('integral_sms')) return;
  200. self::create()->send($id['phone'], $tempId, [
  201. 'integral' => $id['integral'],
  202. 'date' => date('m月d日', strtotime($id['date'])),
  203. 'site' => systemConfig('site_name'),
  204. ]);
  205. }
  206. }
  207. public static function sendMerMessage($merId, string $tempId, array $data)
  208. {
  209. $noticeServiceInfo = app()->make(StoreServiceRepository::class)->getNoticeServiceInfo($merId);
  210. $yunxinSmsService = self::create();
  211. foreach ($noticeServiceInfo as $service) {
  212. if (!$service['phone']) continue;
  213. $yunxinSmsService->send($service['phone'], $tempId, array_merge(['admin_name' => $service['nickname']], $data));
  214. }
  215. }
  216. /**
  217. * @return string
  218. * @author xaboy
  219. * @day 2020-05-18
  220. */
  221. protected function getToken()
  222. {
  223. return md5($this->config['sms_account'] . $this->config['sms_token']);
  224. }
  225. /**
  226. * @author xaboy
  227. * @day 2020-05-18
  228. */
  229. public function checkConfig()
  230. {
  231. if (!isset($this->config['sms_account']) || !$this->config['sms_account']) {
  232. throw new ValidateException('请登录短信账户');
  233. }
  234. if (!isset($this->config['sms_token']) || !$this->config['sms_token']) {
  235. throw new ValidateException('请登录短信账户');
  236. }
  237. }
  238. /**
  239. * 发送注册验证码
  240. * @param $phone
  241. * @return mixed
  242. */
  243. public function captcha($phone)
  244. {
  245. return json_decode(HttpService::getRequest(self::API . 'sms/captcha', compact('phone')), true);
  246. }
  247. /**
  248. * 短信注册
  249. * @param $account
  250. * @param $password
  251. * @param $url
  252. * @param $phone
  253. * @param $code
  254. * @param $sign
  255. * @return mixed
  256. */
  257. public function register($account, $password, $url, $phone, $code, $sign)
  258. {
  259. return $this->registerData(compact('account', 'password', 'url', 'phone', 'code', 'sign'));
  260. }
  261. /**
  262. * @param array $data
  263. * @return mixed
  264. * @author xaboy
  265. * @day 2020-05-18
  266. */
  267. public function registerData(array $data)
  268. {
  269. return json_decode(HttpService::postRequest(self::API . 'sms/register', $data), true);
  270. }
  271. /**
  272. * 公共短信模板列表
  273. * @param array $data
  274. * @return mixed
  275. */
  276. public function publictemp(array $data = [])
  277. {
  278. $this->checkConfig();
  279. $data['account'] = $this->config['sms_account'];
  280. $data['token'] = $this->config['sms_token'];
  281. $data['source'] = 'crmeb_merchant';
  282. return json_decode(HttpService::postRequest(self::API . 'sms/publictemp', $data), true);
  283. }
  284. /**
  285. * 公共短信模板添加
  286. * @param $id
  287. * @param $tempId
  288. * @return mixed
  289. */
  290. public function use($id, $tempId)
  291. {
  292. $this->checkConfig();
  293. $data = [
  294. 'account' => $this->config['sms_account'],
  295. 'token' => $this->config['sms_token'],
  296. 'id' => $id,
  297. 'tempId' => $tempId,
  298. ];
  299. return json_decode(HttpService::postRequest(self::API . 'sms/use', $data), true);
  300. }
  301. /**
  302. * @param string $templateId
  303. * @return mixed
  304. * @author xaboy
  305. * @day 2020-05-18
  306. */
  307. public function getTemplateCode(string $templateId)
  308. {
  309. return Config::get('sms.template_id.' . $templateId);
  310. }
  311. /**
  312. * 原 send 方法 (弃用)
  313. * 发送短信
  314. * @param string $phone
  315. * @param string $templateId
  316. * @param array $data
  317. * @return bool|string
  318. * @throws SmsException
  319. */
  320. public function sendDe(string $phone, string $templateId, array $data = [])
  321. {
  322. if (!$phone) {
  323. throw new SmsException('Mobile number cannot be empty');
  324. }
  325. $this->checkConfig();
  326. $formData['uid'] = $this->config['sms_account'];
  327. $formData['token'] = $this->config['sms_token'];
  328. $formData['mobile'] = $phone;
  329. $formData['template'] = $this->getTemplateCode($templateId);
  330. if (is_null($formData['template']))
  331. throw new SmsException('Missing template number');
  332. $formData['param'] = json_encode($data);
  333. $resource = json_decode(HttpService::postRequest(self::API . 'sms/send', $formData), true);
  334. if ($resource['status'] === 400) {
  335. throw new SmsException($resource['msg']);
  336. } else {
  337. app()->make(SmsRecordDao::class)->create([
  338. 'uid' => $formData['uid'],
  339. 'phone' => $phone,
  340. 'content' => $resource['data']['content'],
  341. 'template' => $resource['data']['template'],
  342. 'record_id' => $resource['data']['id']
  343. ]);
  344. }
  345. return $resource;
  346. }
  347. /**
  348. * 账号信息
  349. * @return mixed
  350. */
  351. public function count()
  352. {
  353. $this->checkConfig();
  354. return json_decode(HttpService::postRequest(self::API . 'sms/userinfo', [
  355. 'account' => $this->config['sms_account'],
  356. 'token' => $this->config['sms_token']
  357. ]), true);
  358. }
  359. /**
  360. * 支付套餐
  361. * @param $page
  362. * @param $limit
  363. * @return mixed
  364. */
  365. public function meal($page, $limit)
  366. {
  367. return json_decode(HttpService::getRequest(self::API . 'sms/meal', [
  368. 'page' => $page,
  369. 'limit' => $limit
  370. ]), true);
  371. }
  372. /**
  373. * 支付码
  374. * @param $payType
  375. * @param $mealId
  376. * @param $price
  377. * @param $attach
  378. * @param $notify
  379. * @return mixed
  380. */
  381. public function pay($payType, $mealId, $price, $attach, $notify = null)
  382. {
  383. $this->checkConfig();
  384. $data['uid'] = $this->config['sms_account'];
  385. $data['token'] = $this->config['sms_token'];
  386. $data['payType'] = $payType;
  387. $data['mealId'] = $mealId;
  388. $data['notify'] = $notify ?? Route::buildUrl('SmsNotify')->build();
  389. $data['price'] = $price;
  390. $data['attach'] = $attach;
  391. return json_decode(HttpService::postRequest(self::API . 'sms/mealpay', $data), true);
  392. }
  393. /**
  394. * 申请模板消息
  395. * @param $title
  396. * @param $content
  397. * @param $type
  398. * @return mixed
  399. */
  400. public function apply($title, $content, $type)
  401. {
  402. $this->checkConfig();
  403. $data['account'] = $this->config['sms_account'];
  404. $data['token'] = $this->config['sms_token'];
  405. $data['title'] = $title;
  406. $data['content'] = $content;
  407. $data['type'] = $type;
  408. return json_decode(HttpService::postRequest(self::API . 'sms/apply', $data), true);
  409. }
  410. /**
  411. * 短信模板列表
  412. * @param $data
  413. * @return mixed
  414. */
  415. public function template(array $data)
  416. {
  417. $this->checkConfig();
  418. return json_decode(HttpService::postRequest(self::API . 'sms/template', $data + [
  419. 'account' => $this->config['sms_account'], 'token' => $this->config['sms_token']
  420. ]), true);
  421. }
  422. /**
  423. * 获取短息记录状态
  424. * @param $record_id
  425. * @return mixed
  426. */
  427. public function getStatus(array $record_id)
  428. {
  429. return json_decode(HttpService::postRequest(self::API . 'sms/status', [
  430. 'record_id' => json_encode($record_id)
  431. ]), true);
  432. }
  433. /**
  434. * @return YunxinSmsService
  435. * @author xaboy
  436. * @day 2020-05-18
  437. */
  438. public static function create()
  439. {
  440. /** @var ConfigValueRepository $make */
  441. $make = app()->make(ConfigValueRepository::class);
  442. $config = $make->more(['sms_account', 'sms_token'], 0);
  443. return new static($config);
  444. }
  445. /**
  446. * @param string $sms_account
  447. * @param string $sms_token
  448. * @return $this
  449. * @author xaboy
  450. * @day 2020-05-18
  451. */
  452. public function setConfig(string $sms_account, string $sms_token)
  453. {
  454. $this->config = compact('sms_token', 'sms_account');
  455. $this->config['sms_token'] = $this->getToken();
  456. return $this;
  457. }
  458. /**
  459. * @return Form
  460. * @throws FormBuilderException
  461. * @author xaboy
  462. * @day 2020-05-18
  463. */
  464. public function form()
  465. {
  466. return Elm::createForm(Route::buildUrl('smsCreate')->build(), [
  467. Elm::input('title', '模板名称'),
  468. Elm::input('content', '模板内容')->type('textarea'),
  469. Elm::radio('type', '模板类型', 1)->options([['label' => '验证码', 'value' => 1], ['label' => '通知', 'value' => 2], ['label' => '推广', 'value' => 3]])
  470. ])->setTitle('申请短信模板');
  471. }
  472. /**
  473. * @return mixed
  474. * @author xaboy
  475. * @day 2020-05-18
  476. */
  477. public function account()
  478. {
  479. $this->checkConfig();
  480. return $this->config['sms_account'];
  481. }
  482. /**
  483. * @Author:Qinii
  484. * @Date: 2020/9/19
  485. * @param $data
  486. * @return mixed
  487. */
  488. public function smsChange($data)
  489. {
  490. $this->checkConfig();
  491. $data['account'] = $this->config['sms_account'];
  492. $data['token'] = $this->config['sms_token'];
  493. return json_decode(HttpService::postRequest(self::API . 'sms/modify', $data), true);
  494. }
  495. /**
  496. * @Author:Qinii
  497. * @Date: 2020/9/19
  498. * @param $phone
  499. * @param $code
  500. * @param $type
  501. * @return bool
  502. */
  503. public function checkSmsCode($phone, $code, $type)
  504. {
  505. $sms_key = $this->sendSmsKey($phone, $type);
  506. if (!$cache_code = Cache::get($sms_key)) return false;
  507. if ($code != $cache_code) return false;
  508. Cache::delete($sms_key);
  509. return true;
  510. }
  511. /**
  512. * @Author:Qinii
  513. * @Date: 2020/9/19
  514. * @param $phone
  515. * @param string $type
  516. * @return string
  517. */
  518. public function sendSmsKey($phone, $type = 'login')
  519. {
  520. switch ($type) {
  521. case 'login': //登录
  522. return 'api_login_' . $phone;
  523. break;
  524. case 'binding': //绑定手机号
  525. return 'api_binding_' . $phone;
  526. break;
  527. case 'intention': //申请入住
  528. return 'merchant_intention_' . $phone;
  529. break;
  530. case 'change_pwd': //修改密码
  531. return 'pwd_' . $phone;
  532. break;
  533. default:
  534. return 'crmeb_' . $phone;
  535. break;
  536. }
  537. }
  538. public function send(string $phone, string $templateId, array $data = [])
  539. {
  540. try{
  541. $make = app()->make(CrmebServeServices::class)->sms();
  542. $resource = $make->send($phone, $this->getTemplateCode($templateId), $data);
  543. if ($resource){
  544. app()->make(SmsRecordDao::class)->create([
  545. 'uid' => $this->config['sms_account'],
  546. 'phone' => $phone,
  547. 'content' => $resource['content'],
  548. 'template' => $resource['template'],
  549. 'record_id' => $resource['id'],
  550. ]);
  551. }
  552. }catch (\Exception $exception){
  553. throw new SmsException($exception->getMessage());
  554. }
  555. }
  556. }