p_ysk/app/model/MessagePushTask.php

589 lines
28 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\model;
// 消息推送
use support\Log;
use support\think\Db;
use EasyWeChat\Factory;
class MessagePushTask
{
// 推送模版消息
public static function send_push_msg()
{
// 查询模版任务
$event_list = Db::name('tb_push_event')->where(['status' => 0, 'push_type' => 1])->select()->toArray();
if($event_list) {
try {
Db::startTrans();
foreach ($event_list as $k => $event) {
Db::name('tb_push_event')->where(['id' => $event['id']])->update(['status' => 1, 'start_time' => date('Y-m-d H:i:s')]);
$res = self::getPullInfoUser($event);
if($res) {
foreach ($res as $rk => &$rv) {
if(empty($rv['open_id'])) {
unset($res[$rk]);
}
}
$user_list = uniqueMultidimensionalArray($res);
// 需要接收推送的用户 准备发送
foreach ($user_list as $k => $user) {
$data = [
'thing2' => $event['keyword1'],
'amount3' => $event['keyword2'],
'time6' => $event['keyword3'],
];
$user_push_list_res_id = Db::name('tb_user_push_event')->insertGetId([
'push_event_id' => $event['id'],
'user_id' => $user['user_id'],
'create_time' => date("Y-m-d H:i:s"),
'content' => json_encode($data),
]);
if($user_push_list_res_id) {
$app = Factory::officialAccount([
'app_id' => config('cons.app_id'),
'secret' => config('cons.secret'),
'response_type' => 'array',
]);
// 正式推送
$push = $app->template_message->send([
'touser' => $user['open_id'],
'template_id' => $event['template_id'],
'data' => $data
]);
Log::info('用户-' . $user['user_id'] . ' 推送模版ID'. $event['template_id'] .' 内容:' . json_encode($data, 256) . ' 推送结果:' . json_encode($push));
if($push['errcode'] == 0) {
Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => 1]);
// 送券
if(isset($event['coupon'])) {
$coupon = json_decode($event['coupon'], true);
self::sendUserCoupon($event['shop_id'], $user['user_id'], $coupon['id'], $coupon['num']);
}
}else {
Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => -1, 'error' => json_encode($push)]);
}
}
sleep(1);
}
Db::name('tb_push_event')->where(['id' => $event['id']])->update(['status' => 2, 'send_time' => date('Y-m-d H:i:s')]);
}
}
Db::commit();
}catch (\Exception $e) {
Log::info('执行出错--' . $e->getMessage());
Db::rollback();
}
}
Log::info('没有推送任务可执行');
return true;
}
// 推送短信消息
public static function send_sms_msg()
{
// 查询短信任务
$event_list = Db::name('tb_push_event')->where(['status' => 0, 'push_type' => 2])->select()->toArray();
if($event_list) {
try {
Db::startTrans();
foreach ($event_list as $k => $event) {
Db::name('tb_push_event')->where(['id' => $event['id']])->update(['status' => 1, 'start_time' => date('Y-m-d H:i:s')]);
$res = self::getPullInfoUser($event);
if($res) {
foreach ($res as $rk => &$rv) {
if(empty($rv['phone'])) {
unset($res[$rk]);
}
}
$user_list = uniqueMultidimensionalArray($res);
// 需要接收推送的用户 准备发送
foreach ($user_list as $k => $user) {
// 查询商家短信余额
$sms_shop = Db::name('tb_shop_sms_money')->where(['shop_id' => $event['shop_id']])->find();
if (!$sms_shop) {
Db::name('tb_shop_sms_money')->insertGetId([
'shop_id' => $event['shop_id'],
'create_time' => date("Y-m-d H:i:s"),
]);
log::info('商户' . $event['shop_id'] . '不存在或余额不足,停止发送');
continue 2;
} else {
// 一条短信的价格
$one_sms_price = config('cons.sms_price');
if($sms_shop['money'] < $one_sms_price) {
log::info('商户' . $event['shop_id'] . '余额不足,停止发送');
continue 2;
}else {
$user_push_list_res_id = Db::name('tb_user_push_event')->insertGetId([
'push_event_id' => $event['id'],
'user_id' => $user['user_id'],
'create_time' => date("Y-m-d H:i:s"),
'content' => json_encode($user),
]);
if ($user_push_list_res_id) {
// 发送短信
$ret = AlibabaSms::main([
'templateCode' => $event['sms_code'],
'templateParam' => json_encode($event['sms_content']),
'phoneNumbers' => $user['phone'],
'signName' => $event['sms_sign'],
]);
Log::info('用户-' . $user['user_id'] . ' 短信发送ID' . $user['template_id'] . ' 内容:' . json_encode($data, 256) . ' 推送结果:' . json_encode($push));
if ($ret) {
Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => 1]);
// 加入明细
$tb_shop_sms_money = Db::name('tb_shop_sms_money_detail')->insertGetId([
'shop_id' => $event['shop_id'],
'type' => 2,
'money' => $one_sms_price,
'create_time' => date("Y-m-d H:i:s"),
]);
if($tb_shop_sms_money) {
// 扣掉余额
Db::name('tb_shop_sms_money')->where([
'shop_id' => $event['shop_id'],
])->dec('money', $one_sms_price)->update();
}
// 送券
if(isset($event['coupon'])) {
$coupon = json_decode($event['coupon'], true);
self::sendUserCoupon($event['shop_id'], $user['user_id'], $coupon['id'], $coupon['num']);
}
} else {
Db::name('tb_user_push_event')->where(['id' => $user_push_list_res_id])->update(['update_time' => date("Y-m-d H:i:s"), 'status' => -1, 'error' => json_encode($push)]);
}
}
sleep(1);
}
}
}
Db::name('tb_push_event')->where(['id' => $event['id']])->update(['status' => 2, 'send_time' => date('Y-m-d H:i:s')]);
}
}
Db::commit();
}catch (\Exception $e) {
Log::info('执行出错--' . $e->getMessage());
Db::rollback();
}
}
Log::info('没有推送任务可执行');
return true;
}
/**
* 找到可以接收订阅消息的用户
* @param $type类型 1按次数发送 2自定义 3按标签
* @return array
*/
public static function getPullInfoUser($event): array
{
$user_arr = [];
switch ($event['type']) {
// 按可接收次数发送(模版推送)/全部绑定手机用户(短信推送)
case 1;
$user_arr = self::getPullInfoUserToNumber($event);
break;
// 自定义
case 2;
$user_arr = self::getPullInfoUserToCustom($event);
break;
// 按标签
case 3;
$user_arr = self::getPullInfoUserToLabel($event);
break;
}
return $user_arr;
}
// 按照可接收次数获取用户信息
public static function getPullInfoUserToNumber($event)
{
$user_num = [];
if($event['push_type'] == 1 && $event['can_send_times'] > 0) {
$user_num = Db::name('tb_user_push_event_num')->alias('upen')->where('upen.num', '>=', $event['can_send_times'])
->join('tb_user_info u', 'upen.user_id = u.id')
->field('upen.user_id as user_id, upen.open_id as open_id')
->select()
->toArray();
}
if($event['push_type'] == 2) {
$user_num = Db::name('tb_user_info')->where('phone', '<>', '')
->field('id as user_id, wechat_ac_open_id as open_id, phone')
->select()
->toArray();
}
return $user_num;
}
// 按照自定义获取用户信息
public static function getPullInfoUserToCustom($event)
{
$data_arr = [];
// 按照性别
if(isset($event['gender']) && is_string($event['gender'])) {
$gender_data_arr = [];
$gender_arr = explode(',', $event['gender']);
foreach ($gender_arr as $k => $gender) {
// 未知
if($gender == 0) {
$gender_data_res = Db::name('tb_user_info')->whereNotIn('sex', [0,1])
->field('id as user_id, wechat_ac_open_id as open_id, phone')
->select()
->toArray();
}
// 男
if($gender == 1) {
$gender_data_res = Db::name('tb_user_info')->where('sex', 1)
->field('id as user_id, wechat_ac_open_id as open_id, phone')
->select()
->toArray();
}
// 女
if($gender == 2) {
$gender_data_res = Db::name('tb_user_info')->where('sex', 0)
->field('id as user_id, wechat_ac_open_id as open_id, phone')
->select()
->toArray();
}
if($gender_data_arr) {
$gender_data_arr = array_merge($gender_data_arr, $gender_data_res);
}else {
$gender_data_arr = $gender_data_res;
}
}
if($gender_data_arr) {
$data_arr = array_merge($data_arr, $gender_data_arr);
}
}
// 按照下单次数
if(isset($event['order_history']) && is_string($event['order_history'])) {
$order_history_arr = explode(',', $event['order_history']);
$order_history_data_arr = [];
foreach ($order_history_arr as $k => $order_history) {
// 从未下单
if($order_history == 0) {
$order_history_data_res = Db::name('tb_user_info')
->alias('u') // 用户表别名u
->leftJoin('tb_order_info o', 'u.id = o.user_id')
->where('o.user_id', 'null')
->distinct()
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->select()
->toArray();
}
// 下过1单
if($order_history == 1) {
$order_history_data_res = Db::name('tb_user_info')
->alias('u')
// 关联订单表,使用内连接确保只包含有订单的用户
->join('tb_order_info o', 'u.id = o.user_id')
// 按用户ID分组
->group('u.id')
// 筛选出订单数量为1的用户
->having('COUNT(o.id) = 1')
// 选择需要的用户字段,同时查询订单数量(可选)
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->select()
->toArray();
}
// 下过2-5单
if($order_history == 2) {
$order_history_data_res = Db::name('tb_user_info')
->alias('u')
// 关联订单表,使用内连接确保只包含有订单的用户
->join('tb_order_info o', 'u.id = o.user_id')
// 按用户ID分组
->group('u.id')
// 筛选出订单数量为1的用户
->having('COUNT(o.id) BETWEEN 2 AND 5')
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->select()
->toArray();
}
// 下过5单起
if($order_history == 3) {
$order_history_data_res = Db::name('tb_user_info')
->alias('u')
// 关联订单表,使用内连接确保只包含有订单的用户
->join('tb_order_info o', 'u.id = o.user_id')
// 按用户ID分组
->group('u.id')
// 筛选出订单数量为1的用户
->having('COUNT(o.id) >= 5')
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->select()
->toArray();
}
if($order_history_data_arr) {
$order_history_data_arr = array_merge($order_history_data_arr, $order_history_data_res);
;
}else {
$order_history_data_arr = $order_history_data_res;
}
}
if($order_history_data_arr) {
$data_arr = array_merge($data_arr, $gender_data_arr);
}
}
// 按照下单时间
if(isset($event['order_times']) && is_string($event['order_times'])) {
$order_times_arr = explode(',', $event['order_times']);
$order_times_data_arr = [];
foreach ($order_times_arr as $k => $order_times) {
// 今天下过
if($order_times == 0) {
$order_times_data_res = Db::name('tb_user_info')
->alias('u') // 用户表别名u
->join('tb_order_info o', 'u.id = o.user_id')
->where('o.create_time', '>=', date('Y-m-d 00:00:00'))
->where('o.create_time', '<=', date('Y-m-d 23:59:59'))
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->distinct()
->select()
->toArray();
}
// 昨天下过
if($order_times == 1) {
$order_times_data_res = Db::name('tb_user_info')
->alias('u') // 用户表别名u
->join('tb_order_info o', 'u.id = o.user_id')
->where('o.create_time', '>=', date('Y-m-d 00:00:00', strtotime('-1 day')))
->where('o.create_time', '<=', date('Y-m-d 23:59:59', strtotime('-1 day')))
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->distinct()
->select()
->toArray();
}
// 2周内没下过
if($order_times == 2) {
$twoWeeksAgo = date('Y-m-d H:i:s', strtotime('-14 days'));
$order_times_data_res = Db::name('tb_user_info')
->alias('u') // 用户表别名u
// 左连接订单表,关联条件包含近两周内的订单
->leftJoin('tb_order_info o', 'u.id = o.user_id')
->where('o.create_time', '>=', $twoWeeksAgo)
->where('o.id', 'null')
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->distinct()
->select()
->toArray();
}
// 半个月-1个月没下过
if($order_times == 3) {
$startTime = date('Y-m-d H:i:s', strtotime('-30 days'));
$endTime = date('Y-m-d H:i:s', strtotime('-15 days'));
$order_times_data_res = Db::name('tb_user_info')
->alias('u') // 用户表别名u
// 左连接订单表,关联条件包含近两周内的订单
->join('tb_order_info o', 'u.id = o.user_id')
// 按用户分组
->group('u.id')
// 筛选最后下单时间在30天前到15天前之间的用户
->having('MAX(o.create_time) >="'. $startTime .'" AND MAX(o.create_time) <= "' . $endTime . '"')
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->select()
->toArray();
}
// 1个月以上没下过
if($order_times == 4) {
$oneMonthAgo = date('Y-m-d H:i:s', strtotime('-30 days'));
$order_times_data_res = Db::name('tb_user_info')
->alias('u') // 用户表别名u
// 左连接订单表,关联条件包含近两周内的订单
->join('tb_order_info o', 'u.id = o.user_id')
// 按用户分组
->group('u.id')
// 筛选最后下单时间在1个月前及更早
->having('MAX(o.create_time) <= "' . $oneMonthAgo . '"')
// ->field('u.id as user_id, u.wechat_ac_open_id as open_id, MAX(o.create_time) as last_order_time')
->field('u.id as user_id, u.wechat_ac_open_id as open_id, u.phone as phone')
->select()
->toArray();
}
if($order_times_data_arr) {
$order_times_data_arr = array_merge($order_times_data_arr, $order_times_data_res);
}else {
$order_times_data_arr = $order_times_data_res;
}
}
if($order_times_data_arr) {
$data_arr = array_merge($data_arr, $order_times_data_arr);
}
// 按照会员
if(isset($event['vip']) && is_string($event['vip'])) {
$vip_data_arr = [];
$vip_arr = explode(',', $event['vip']);
foreach ($vip_arr as $k => $vip) {
// 非会员
if($vip == 0) {
$vip_data_res = Db::name('tb_user_info')->whereNotIn('is_vip', 0)
->field('id as user_id, wechat_ac_open_id as open_id,phone')
->select()
->toArray();
}
// 会员
if($vip == 1) {
if($event['push_type'] == 1) {
$vip_data_res = Db::name('tb_user_info')->where('is_vip', 1)
->field('id as user_id, wechat_ac_open_id as open_id,phone')
->select()
->toArray();
}
// 推送类型为短信推送
if($event['push_type'] == 2) {
// 全部会员
if($event['vip_lavel'] == 0) {
$vip_data_res = Db::name('tb_user_info')->where('is_vip', 1)
->field('id as user_id, wechat_ac_open_id as open_id,phone')
->select()
->toArray();
}
// 仅限等级
if($event['vip_lavel'] == 1) {
$vip_data_res = Db::name('tb_user_info')->where(['is_vip' => 1, 'member_level_id' => $event['vip_lavel_id']])
->field('id as user_id, wechat_ac_open_id as open_id,phone')
->select()
->toArray();
}
// 以上等级
if($event['vip_lavel'] == 2) {
// 找到会员详情
$vip_config_info = Db::name('tb_member_level_config')->where(['id' => $event['vip_lavel_id']])->find();
if($vip_config_info) {
$vip_config_info = Db::name('tb_member_level_config')->where('experience_value', '>', $vip_config_info['experience_value'])->column('id');
if($vip_config_info) {
$vip_data_res = Db::name('tb_user_info')->where(['is_vip' => 1])->whereIn('member_level_id', $vip_config_info)
->field('id as user_id, wechat_ac_open_id as open_id,phone')
->select()
->toArray();
}
}
}
}
}
if($vip_data_arr) {
$vip_data_arr = array_merge($vip_data_arr, $vip_data_res);
}else {
$vip_data_arr = $vip_data_res;
}
}
if($vip_data_arr) {
$data_arr = array_merge($data_arr, $vip_data_arr);
}
}
// 按照手机号
if(isset($event['telphone']) && is_string($event['telphone'])) {
$telphone_data_arr = [];
$telphone_arr = explode(',', $event['telphone']);
foreach ($telphone_arr as $k => $telphone) {
// 非绑定
if($telphone == 0) {
$telphone_data_res = Db::name('tb_user_info')->where(function ($query) {
$query->where('phone', 'null') // 为 NULL
->whereOr('phone', ''); // 为空字符串
})
->field('id as user_id, wechat_ac_open_id as open_id')
->select()
->toArray();
}
// 已绑定
if($telphone == 1) {
$telphone_data_res = Db::name('tb_user_info')->where('phone', '<>', '')
->field('id as user_id, wechat_ac_open_id as open_id, phone')
->select()
->toArray();
}
if($telphone_data_arr) {
$telphone_data_arr = array_merge($telphone_data_arr, $telphone_data_res);
}else {
$telphone_data_arr = $telphone_data_res;
}
}
if($telphone_data_arr) {
$data_arr = array_merge($data_arr, $telphone_data_arr);
}
}
}
return $data_arr;
}
// 按照标签获取用户信息
public static function getPullInfoUserToLabel($event)
{
$data_arr = [];
$label = Db::name('tb_user_label')->whereIn('label_id', explode(',', $event['user_label']))
->distinct()
->column('user_id');
if($label) {
$data_arr = Db::name('tb_user_info')->whereIn('id', $label)
->field('id as user_id, wechat_ac_open_id as open_id, phone')
->select()
->toArray();
}
return $data_arr;
}
// 给用户送送优惠券
public static function sendUserCoupon($shop_id, int | array $user_id, $coupon_id, $number = 1)
{
if ($number === null || $number <= 0) {
Log::info('推送用户送券发放数量不能小于0');
return false;
}
$url = 'http://192.168.1.31/market/admin/coupon/grant';
$res = http_post($url, [
'userId' => $user_id,
'couponId' => $coupon_id,
'num' => $number,
'shopId' => $shop_id,
]);
Log::info('发券:' . $res);
$res = json_decode($res, true);
if($res['code'] == 200) {
Log::info('userId:' . $user_id . ' couponId:' . $coupon_id . ' shopId:' . $shop_id . ' 发券成功');
}else {
Log::info('userId:' . $user_id . ' couponId:' . $coupon_id . ' shopId:' . $shop_id . ' 发券失败' . ' 信息:' . $res['msg']);
}
return true;
}
}