BatchWechatCustomSendService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <?php
  2. /**
  3. * 批量发送微信素材
  4. */
  5. namespace App\Modules\WechatMaterial\Services;
  6. use App\Modules\WechatMaterial\Models\WechatMaterial;
  7. use App\Modules\WechatMaterial\Models\WechatMaterialSendMsg;
  8. use App\Modules\WechatMaterial\Models\BatchWechatMaterial;
  9. use App\Modules\OfficialAccount\Services\ForceSubscribeService;
  10. use App\Modules\OfficialAccount\Models\ForceSubscribeUsers;
  11. use App\Modules\OfficialAccount\Models\OfficialAccount;
  12. use App\Modules\OfficialAccount\Models\OfficialCustomMsg;
  13. use App\Modules\OfficialAccount\Models\CustomSendMsgs;
  14. use App\Modules\User\Services\ReadRecordService;
  15. use App\Modules\User\Services\UserService;
  16. use App\Modules\Book\Services\BookConfigService;
  17. use App\Modules\OfficialAccount\Services\OfficialAccountService;
  18. use App\Modules\Channel\Services\ChannelService;
  19. use GuzzleHttp\Client;
  20. use Redis;
  21. use App\Jobs\SendBatchWechatMaterial;
  22. class BatchWechatCustomSendService
  23. {
  24. /**
  25. * @return int|void toCheckAndSendCustomMsg
  26. * 查找并发送客服消息
  27. */
  28. static function toCheckAndSendBatchCustomMsg()
  29. {
  30. //
  31. try {
  32. //查找模板消息并发送
  33. $statusPram = 'to_send';
  34. $allStandByWechatCustomMsgs = WechatMaterialSendMsg::wechatCustomMsgsByStatus($statusPram);
  35. \Log::info($allStandByWechatCustomMsgs);
  36. $allStandByWechatCustomMsgsArray = [];
  37. if ($allStandByWechatCustomMsgs) {
  38. //先单独更新数据库 把要发送的状态改为sending 以免发送期间超时,导致重复发送
  39. for ($x = 0; $x < count($allStandByWechatCustomMsgs); $x++) {
  40. $customSendMsgsPrams = $allStandByWechatCustomMsgs[$x];
  41. $send_time = $customSendMsgsPrams['send_time'];
  42. if (strtotime($send_time) - time() > 60*15) { //发送时间大于当前时间15分钟
  43. continue;
  44. } else {
  45. \Log::info('========现将客服消息设置成发送状态 "sending" 用户不能操作(删除,编辑,停止) = ' . $customSendMsgsPrams['id']);
  46. $customSendMsgsPrams['status'] = 'sending';
  47. $customSendMsgsPrams->save();
  48. $officialAccountArray = $customSendMsgsPrams->toArray();
  49. Redis::hset('send_batch_wechat_msg:task_id:' . $customSendMsgsPrams['id'], 'wechat_msg', json_encode($officialAccountArray));
  50. $allStandByWechatCustomMsgsArray[] = $customSendMsgsPrams;
  51. }
  52. }
  53. for ($x = 0; $x < count($allStandByWechatCustomMsgsArray); $x++) {
  54. $customSendMsgsPrams = $allStandByWechatCustomMsgsArray[$x];
  55. // 转化图文的链接url
  56. // $customSendMsgsPrams['content'] = self::convert_custom_content($customSendMsgsPrams['content'],$customSendMsgsPrams['id'],$customSendMsgsPrams['distribution_channel_id']);
  57. $media_id = $customSendMsgsPrams['wechat_media_id'];
  58. $appids = $customSendMsgsPrams['appid'];
  59. $batch_id = $customSendMsgsPrams['batch_id'];
  60. $task_id = $customSendMsgsPrams['id'];
  61. // 获取发送的批次信息
  62. $batchWechatMaterial = BatchWechatMaterial::find($batch_id);
  63. $send_time= isset($batchWechatMaterial['send_time'])?$batchWechatMaterial['send_time']:date('Y-m-d H:i:s');
  64. $is_full_send= isset($batchWechatMaterial['is_all_user'])?$batchWechatMaterial['is_all_user']:0;
  65. \Log::info('batch_wechat_msg,appids:'.$appids.' is_full_send:'.$is_full_send.' media_id:'.$media_id);
  66. $appidArray = explode(',', $appids);
  67. $usercountnum = 0;
  68. for ($j=0; $j < count($appidArray); $j++) {
  69. $skip = 0;
  70. $next_openid = '';
  71. $loop = 0;
  72. while ( $skip <= 2500000) {
  73. $loop++;
  74. \Log::info('toCheckAndSendBatchCustomMsg_loop:'.$skip.' loop:'.$loop.' next_openid:'.$next_openid);
  75. $users = array();
  76. // 全服务号粉丝发,要记录next_openid
  77. if($is_full_send){
  78. // 防止异常
  79. if($loop > 1 && empty($next_openid)){
  80. \Log::info('send_template_appid:'.$appidArray[$j].' break,skip:'.$skip);
  81. break;
  82. }
  83. try{
  84. $user_res = ForceSubscribeService::getFullOfficialAccountUsers($appidArray[$j],$next_openid);
  85. $users = $user_res['openids'];// TODO格式化成一样的格式
  86. $next_openid = $user_res['next_openid'];
  87. } catch (\Exception $e) {
  88. \Log::info($e);
  89. }
  90. }else{
  91. //5,获取所选条件下筛选出的用户
  92. $sign_time = 'z';
  93. $subscribe_time = isset($batchWechatMaterial['subscribe_time'])?$batchWechatMaterial['subscribe_time']:'';
  94. $sex= isset($batchWechatMaterial['sex'])?$batchWechatMaterial['sex']:'';
  95. $balance= isset($batchWechatMaterial['balance'])?$batchWechatMaterial['balance']:'';
  96. $category_id= isset($batchWechatMaterial['category_id'])?$batchWechatMaterial['category_id']:'';
  97. $order_type= isset($batchWechatMaterial['pay_type'])?$batchWechatMaterial['pay_type']:'';
  98. $sign_time= isset($batchWechatMaterial['sign_time'])?$batchWechatMaterial['sign_time']:'';
  99. $interaction_time= isset($batchWechatMaterial['interaction_time'])?$batchWechatMaterial['interaction_time']:'';
  100. $users = ForceSubscribeService::forceUserCountByBatchWechatCustomPrams($appidArray[$j],$customSendMsgsPrams['distribution_channel_id'],$subscribe_time,$sex,$balance,$category_id,$order_type,$sign_time,$interaction_time,$skip);
  101. }
  102. \Log::info('toCheckAndSendBatchCustomMsg_users_num:'.count($users));
  103. // continue;
  104. $queue_user_one_num = 10000;
  105. $user_loop = 1;
  106. $last_openids = $openids = [];
  107. if (count($users)>0) {
  108. $usercountnum += count($users);
  109. for ($i=0; $i < count($users); $i++) {
  110. // 循环用户发送客服消息
  111. $data = array();
  112. if ($i == count($users)-1) {
  113. $data['type'] = 'last_task';
  114. }else{
  115. $data['type'] = 'one_task';
  116. }
  117. \Log::info('i:'.$i.' $user_loop:'.$user_loop.' openid:'.$users[$i]['openid'].' type:'.$data['type']);
  118. // 一次组装10000个用户 (接口1次最多10000个,1天最多发100次)
  119. if($user_loop <= $queue_user_one_num){
  120. $openids[] = $users[$i]['openid'];
  121. $user_loop++;
  122. // 最后1组直接执行
  123. if($data['type'] == 'one_task'){
  124. continue;
  125. }else{
  126. $last_openids = $openids;
  127. }
  128. }else{
  129. $user_loop = 1;
  130. $last_openids = $openids;
  131. }
  132. // $data['content'] = $customSendMsgsPrams['content'];
  133. $data['openids'] = $last_openids;
  134. $data['appid'] = $appidArray[$j];
  135. $data['media_id'] = $media_id;
  136. $data['type'] = 'last_task'; // 默认发1个直接更新,防止更新失败情况
  137. $data['task_id'] = $task_id;
  138. $data['batch_id'] = $batch_id;
  139. $data['send_time'] = $send_time;
  140. $send_data=array(
  141. 'send_time'=>$send_time,
  142. 'data' => $data
  143. );
  144. $now_time = strtotime($send_time)-time();
  145. $delay = $now_time < 0 ? 0:$now_time;
  146. \Log::info('SendBatchWechatMaterial:'.json_encode($last_openids).' task_id:'.$task_id);
  147. \Log::info($send_data);
  148. $job = (new SendBatchWechatMaterial($send_data))->onConnection('rabbitmq')->delay($delay)->onQueue('{send_batch_wechat_material}');
  149. dispatch($job);
  150. $last_openids = $openids = [];
  151. }
  152. }else{
  153. \Log::info('toCheckAndSendBatchCustomMsg_no_user:'.$customSendMsgsPrams['task_id']);
  154. break;
  155. }
  156. $skip += count($users);
  157. }
  158. }
  159. $customSendMsgsPrams['send_user_num'] = $usercountnum;
  160. // 若没有用户,则直接更新为已发送
  161. if($usercountnum == 0){
  162. \Log::info('has_no_batch_custom_users:'.$customSendMsgsPrams['id']);
  163. $customSendMsgsPrams['status'] = 'has_send';
  164. }
  165. \Log::info('toCheckAndSendBatchCustomMsg_update_user_num:'.$customSendMsgsPrams['id'].' usercountnum:'.$usercountnum);
  166. $customSendMsgsPrams->save();
  167. }
  168. }else{
  169. \Log::info('toCheckAndSendBatchCustomMsg_no_msgs');
  170. }
  171. } catch (\Exception $e) {
  172. \Log::info('toCheckAndSendBatchCustomMsg_ept:'.$e->getMessage());
  173. }
  174. }
  175. /**
  176. * 转换客服消息内容
  177. */
  178. public static function convert_custom_content($content,$mark_str,$distribution_channel_id){
  179. \Log::info('convert_custom_content_start:');
  180. $_contents = json_decode($content);
  181. \Log::info('convert_custom_content_before:');
  182. \Log::info($_contents);
  183. $new_contents = null;
  184. $origin_mark_str = $mark_str;
  185. $send_type = 'batch_custom';
  186. // 智能推送不加前缀
  187. if(strpos($origin_mark_str,'smart_push_') > -1){
  188. $send_type = 'smart_push';
  189. $origin_mark_str = str_replace('smart_push_','',$origin_mark_str);
  190. }
  191. \Log::info('origin_mark_str:'.$origin_mark_str);
  192. foreach($_contents as $key=>$_content){
  193. // 新版要自动添加域名
  194. $_content[2]->url = self::checkAddDomain($distribution_channel_id,$_content[2]->url);
  195. $mark_str = $origin_mark_str.'&source=wechatmsg';// source能让用户继续阅读
  196. $_contents[$key][2]->url = self::redirect_url_add_param($_content[2]->url,$mark_str,$send_type,false);
  197. $new_contents[] = $_contents[$key];
  198. }
  199. \Log::info('convert_custom_content_after:');
  200. \Log::info($new_contents);
  201. $_convert_contents = json_encode($new_contents);
  202. return $_convert_contents;
  203. }
  204. /**
  205. * 跳转地址加参
  206. * @param unknown_type $redirect_url
  207. * @param unknown_type $type
  208. * @return string
  209. */
  210. public static function redirect_url_add_param($redirect_url,$mark_str,$type='custom',$trusteeship=false){
  211. $pre_str = '';
  212. if($type == 'batch_custom'){
  213. $pre_str = 'batch_custom_';
  214. }
  215. // 模板客服消息,单独加参
  216. $inner_order_id = '';
  217. if(!$trusteeship){
  218. $inner_order_id = '&inner_order_id='.$pre_str.$mark_str;
  219. }
  220. $send_time_str = '';
  221. // 跳转链接加参
  222. if(strpos($redirect_url,'?') > -1){
  223. $redirect_url .= '&fromtype='.$pre_str.$mark_str.$inner_order_id.$send_time_str;
  224. }else{
  225. $redirect_url .= '?fromtype='.$pre_str.$mark_str.$inner_order_id.$send_time_str;
  226. }
  227. return $redirect_url;
  228. }
  229. // 新版要自动添加域名
  230. public static function checkAddDomain($distribution_channel_id,$redirect_url){
  231. // 非托管,如果url没有域名,则加上
  232. if(strpos($redirect_url, 'http') !== false){
  233. \Log::info('not_need_add_domain:'.$distribution_channel_id.' url:'.$redirect_url);
  234. }else{
  235. \Log::info('need_add_domain_before:'.$distribution_channel_id.' url:'.$redirect_url);
  236. $redirect_url = env('PROTOCOL').'://site'.encodeDistributionChannelId($distribution_channel_id).'.'.env('CUSTOM_HOST').'.com'.$redirect_url;
  237. \Log::info('need_add_domain_after:'.$distribution_channel_id.' url:'.$redirect_url);
  238. }
  239. return $redirect_url;
  240. }
  241. }