From cd167267b242e3f1de9e66e5d69d3e39766e7a4b Mon Sep 17 00:00:00 2001 From: AKW <2497744746@qq.com> Date: Mon, 26 Feb 2024 13:51:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=AE=A2bug=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jqr/models.py | 79 +++++++++++++++++++++---- apps/jqr/tasks.py | 142 +++++++++++++++++++++++---------------------- 2 files changed, 141 insertions(+), 80 deletions(-) diff --git a/apps/jqr/models.py b/apps/jqr/models.py index 0c0f513..9b1fcb5 100644 --- a/apps/jqr/models.py +++ b/apps/jqr/models.py @@ -30,7 +30,7 @@ class JqrWechatbizuserinfo(models.Model): deletetype = models.IntegerField( verbose_name='删除方式', choices=JqrWechatbizuserinfoDeleteTypeChoices.choices, null=True, blank=True) addtype = models.IntegerField( - verbose_name='添加方式', choices=JqrUserAddTypeChoices.choices, default=JqrAddTypeChoices.API) + verbose_name='添加方式', choices=JqrAddTypeChoices.choices, default=JqrAddTypeChoices.API) class Meta: db_table = 'jqr_wechatbizuserinfo' @@ -43,7 +43,7 @@ class JqrHookUser(models.Model): uid = models.IntegerField(verbose_name='用户Id') corpid = models.CharField(max_length=255, verbose_name='企业唯一标识') userid = models.CharField(max_length=50, verbose_name='接粉号userid') - vid = models.CharField(max_length=255, verbose_name='hook vid', null=True, blank=True) + vid = models.CharField(max_length=255, verbose_name='hook vid') new_user = models.BooleanField(default=True, verbose_name='新科欢迎开关') new_user_order = models.BooleanField( default=False, verbose_name='新科欢迎催单开关') @@ -51,7 +51,8 @@ class JqrHookUser(models.Model): time_private = models.BooleanField(default=True, verbose_name='定时私聊开关') time_quan = models.BooleanField(default=True, verbose_name='定时朋友圈开关') keyword = models.BooleanField(default=True, verbose_name='关键字回复开关') - utime = models.DateTimeField(verbose_name='更新时间', null=True, blank=True, auto_now=True) + need_warning = models.BooleanField(default=False, verbose_name='是否需要报警') + utime = models.DateTimeField(verbose_name='更新时间', null=True, blank=True) name = models.CharField( max_length=255, verbose_name='用户名', null=True, blank=True) mobile = models.CharField( @@ -73,6 +74,8 @@ class JqrHookUser(models.Model): hook_connecttime = models.DateTimeField(null=True, verbose_name="hook最近一次通信时间", blank=True) hook_version = models.CharField(max_length=255, null=True, verbose_name="hook版本号", blank=True) ip = models.CharField(verbose_name='ip', null=True, blank=True, max_length=128) + seq = models.BigIntegerField(verbose_name='seq', null=True, blank=True, default=0) + warning_setting_id = models.IntegerField(verbose_name='报警配置', null=True, blank=True) class Meta: unique_together = ('corpid', 'userid', 'vid') @@ -104,7 +107,7 @@ class JqrExternalUser(models.Model): ctime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) utime = models.DateTimeField(verbose_name='更新时间', auto_now=True) addtype = models.IntegerField( - verbose_name='添加方式', choices=JqrUserAddTypeChoices.choices, default=JqrAddTypeChoices.API) + verbose_name='添加方式', choices=JqrAddTypeChoices.choices, default=JqrAddTypeChoices.API) class Meta: db_table = 'jqr_external_user' @@ -114,9 +117,9 @@ class JqrExternalUser(models.Model): class JqrExternalFollowUser(models.Model): - id = models.BigAutoField(primary_key=True) corpid = models.CharField(max_length=32, verbose_name='企业微信corpid') external_userid = models.CharField(max_length=60, verbose_name='外部用户id') + id = models.BigAutoField(primary_key=True) userid = models.CharField(max_length=50, verbose_name='接粉号userid') remark = models.TextField( verbose_name='该成员对此外部联系人的备注', null=True, blank=True) @@ -125,9 +128,9 @@ class JqrExternalFollowUser(models.Model): createtime = models.BigIntegerField(verbose_name='添加好友时间') tags = models.JSONField(verbose_name='标签') remark_mobiles = models.JSONField(verbose_name='该成员对此客户备注的手机号码') - wechat_channels = models.JSONField(verbose_name='微信渠道', null=True, blank=True) add_way = models.IntegerField( verbose_name='添加方式', choices=JqrUserAddTypeChoices.choices) + wechat_channels = models.JSONField(verbose_name='微信渠道', null=True, blank=True) state = models.CharField( max_length=255, verbose_name='企业自定义的state参数', null=True, blank=True) oper_userid = models.CharField( @@ -135,10 +138,11 @@ class JqrExternalFollowUser(models.Model): ctime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) utime = models.DateTimeField(verbose_name='更新时间', auto_now=True) dtime = models.DateTimeField(verbose_name='删除时间', null=True, blank=True) + msg_last_look_time = models.DateTimeField(verbose_name='当前客户消息最后一次看到的时间', null=True, blank=True) addtype = models.IntegerField( - verbose_name='添加方式', choices=JqrUserAddTypeChoices.choices, default=JqrAddTypeChoices.API) + verbose_name='数据添加方式', choices=JqrAddTypeChoices.choices, default=JqrAddTypeChoices.API) deletetype = models.IntegerField( - verbose_name='删除方式', choices=JqrWechatbizuserinfoDeleteTypeChoices.choices, null=True, blank=True) + verbose_name='删除方式', choices=JqrWechatbizuserinfoDeleteTypeChoices.choices, default=0) class Meta: db_table = 'jqr_external_follow_user' @@ -154,14 +158,17 @@ class JqrExternalQun(models.Model): max_length=50, verbose_name='接粉号vid', null=True, blank=True) chat_id = models.CharField(max_length=60, verbose_name='群id') name = models.CharField(max_length=255, verbose_name='群名') + member_version = models.CharField(max_length=255, verbose_name='当前群成员版本号') owner = models.CharField(max_length=50, verbose_name='接粉号userid') create_time = models.BigIntegerField(verbose_name='群创建时间') notice = models.TextField(verbose_name='群通知', null=True, blank=True) ctime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) utime = models.DateTimeField(verbose_name='更新时间', auto_now=True) dtime = models.DateTimeField(verbose_name='删除时间', null=True, blank=True) + msg_last_look_time = models.DateTimeField(verbose_name='当前群消息最后一次看到的时间', null=True, blank=True) addtype = models.IntegerField( - verbose_name='添加方式', choices=JqrUserAddTypeChoices.choices, default=JqrAddTypeChoices.API) + verbose_name='添加方式', choices=JqrAddTypeChoices.choices, default=JqrAddTypeChoices.API) + seq = models.BigIntegerField(verbose_name='seq', null=True, blank=True, default=0) class Meta: db_table = 'jqr_external_qun' @@ -260,6 +267,7 @@ class JqrTimePrivateSendGroupMsg(JqrBaseSendMsg): sendtime = models.DateTimeField(verbose_name='下次具体发送时间', null=True, blank=True) type = models.IntegerField(verbose_name='类型', choices=JqrTimeSendGroupMsgTypeChoices.choices, default=JqrTimeSendGroupMsgTypeChoices.PRIVATE) + status = models.IntegerField(verbose_name='任务状态', default=0) class Meta: db_table = 'jqr_timeprivatesendgroupmsg' @@ -367,10 +375,10 @@ class JqrSendnewusermsgrecord(models.Model): verbose_name='平台用户ID') sendid = models.BigIntegerField(verbose_name='发送计划ID') sendtime = models.DateTimeField(verbose_name='发送时间') - sendmethod = models.IntegerField(verbose_name='发送方式 0:极速 1:高级', choices=JqrSendnewusermsgrecordSendMethodChoices.choices) corpid = models.CharField(max_length=32, blank=True, null=True, verbose_name='企业ID') userid = models.CharField(max_length=32, blank=True, null=True, verbose_name='接粉号ID') wxvid = models.CharField(max_length=64, blank=True, null=True, verbose_name='外部用户wxvid') + sendmethod = models.IntegerField(verbose_name='发送方式 0:极速 1:高级', choices=JqrSendnewusermsgrecordSendMethodChoices.choices) sendtype = models.IntegerField(blank=True, null=True, verbose_name='发送类型 0:新客欢迎 1:新客催单', choices=JqrSendnewusermsgrecordSendTypeChoices.choices) sendstate = models.IntegerField(blank=True, null=True, @@ -378,8 +386,8 @@ class JqrSendnewusermsgrecord(models.Model): choices=JqrSendnewusermsgrecordSendStateChoices.choices) sendnums = models.IntegerField(blank=True, null=True, verbose_name='重复次数') sendcontent = models.JSONField(verbose_name='发送内容') - ctime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) - utime = models.DateTimeField(verbose_name='更新时间', auto_now=True) + ctime = models.DateTimeField(verbose_name='创建时间') + utime = models.DateTimeField(verbose_name='更新时间') sendkey = models.CharField(max_length=32, blank=True, null=True, verbose_name='服务端创建的Key') clientkey = models.CharField(max_length=32, blank=True, null=True, verbose_name='微信返回的msgid') timestamp = models.BigIntegerField(blank=True, null=True, verbose_name='时间戳') @@ -389,6 +397,7 @@ class JqrSendnewusermsgrecord(models.Model): db_table = 'jqr_sendnewusermsgrecord' verbose_name = '联系人消息发送记录' verbose_name_plural = '联系人消息发送记录' + ordering = ['-utime', ] class JqrSendmsgrecord(models.Model): @@ -404,6 +413,7 @@ class JqrSendmsgrecord(models.Model): db_table = 'jqr_sendmsgrecord' verbose_name = '私聊发送记录' verbose_name_plural = '私聊发送记录' + ordering = ['-sendtime'] class JqrSendmsgrecordinfo(models.Model): @@ -428,3 +438,48 @@ class JqrSendmsgrecordinfo(models.Model): db_table = 'jqr_sendmsgrecordinfo' verbose_name = '发送记录信息' verbose_name_plural = '发送记录信息' + ordering = ['-utime', 'userid'] + + +class JqrSendKeywordMsgRecord(models.Model): + id = models.BigAutoField(primary_key=True) + platfromuserid = models.BigIntegerField() + sendid = models.BigIntegerField() + sendtime = models.DateTimeField() + corpid = models.CharField(max_length=32, null=True, blank=True) + userid = models.CharField(max_length=32) + wxvid = models.CharField(max_length=32, null=True, blank=True) + sendmethod = models.IntegerField(verbose_name='发送方式 0:极速 1:高级', choices=JqrSendnewusermsgrecordSendMethodChoices.choices) + sendstate = models.IntegerField(blank=True, null=True, + verbose_name='发送状态 0:等待发送 1:已发送 2:发送成功 3:发送失败 4:取消发送', + choices=JqrSendnewusermsgrecordSendStateChoices.choices) + sendnums = models.IntegerField(null=True) + sendcontent = models.JSONField() + ctime = models.DateTimeField() + utime = models.DateTimeField() + sendkey = models.CharField(max_length=32) + clientkey = models.CharField(max_length=32) + timestamp = models.BigIntegerField() + contentname = models.CharField(max_length=64, null=True, blank=True) + groupid = models.CharField(max_length=64, null=True, blank=True) + + class Meta: + db_table = 'jqr_sendkeywordmsgrecord' + verbose_name = '关键词发送记录' + ordering = ('-utime', ) + + +class JqrTestAccount(models.Model): + id = models.BigAutoField(verbose_name='ID', primary_key=True) + uid = models.IntegerField(verbose_name='平台用户ID', null=False) + userid = models.CharField(max_length=255, verbose_name='接粉号Id') + external_userid = models.CharField(max_length=255, verbose_name='外部联系人Id', null=True, blank=True) + chat_id = models.CharField(max_length=255, verbose_name='群聊id', null=True, blank=True) + corpid = models.CharField(max_length=32, verbose_name='企业微信corpid', null=True, blank=True) + ctime = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) + utime = models.DateTimeField(verbose_name='更新时间', auto_now=True) + + class Meta: + db_table = 'jqr_test_account' + verbose_name = '测试账号' + verbose_name_plural = '测试账号' diff --git a/apps/jqr/tasks.py b/apps/jqr/tasks.py index 03b524e..101d47c 100644 --- a/apps/jqr/tasks.py +++ b/apps/jqr/tasks.py @@ -53,85 +53,91 @@ def save_add_contact(data, corpinfo, *args, **kwargs): def save_add_contact_by_channel(data, corpinfo, *args, **kwargs): - userid = data.get('userid') + try: + userid = data.get('userid') - externaluserid = data.get('externaluserid') - corpid = data.get('corpid') - QcWechatbizeventAddcontact.objects.update_or_create( - userid=userid, - externaluserid=externaluserid, - corpid=corpid, - defaults={ - **data, - 'isdelete': QcWechatbizeventAddcontactIsDeleteChoices.NOT_DELETE, - 'deletetime': None, - 'ctime': datetime.now(), - } - ) - qrcodeid = data.get('qrcodeid') - if qrcodeid: - JQRQrcodeCallbackPubSub.publish({ - 'qrcodeid': qrcodeid, - 'userid': userid, - 'externaluserid': externaluserid, - 'corpinfo': corpinfo, - 'handler': f'{qrcode_channel_handler.__module__}.{qrcode_channel_handler.__name__}' - }) - # 修复客户关系 - edit_add_contact(data, corpinfo, *args, **kwargs) - # # 转化外部用户Id - # WS.transfer_external_userid_to_vid(corpid, userid, externaluserid) - # 发送新客欢迎 - hook_user = JqrHookUser.objects.filter(corpid=corpid, userid=userid).first() - if hook_user is not None: - # utime 是否在 9 分钟内 - now = datetime.now() - nine_minute_ago = now - timedelta(minutes=9) - uid = hook_user.uid - createtime = data.get('createtime') - rc = SimpleLock(f'{corpid}:{userid}:{externaluserid}:{createtime}') - success = rc.try_lock(60 * 10) - if hook_user.utime > nine_minute_ago and hook_user.new_user and success: - # 发送消息 - send_new_user_msg(corpid, userid, external_userid=externaluserid, uid=uid) + externaluserid = data.get('externaluserid') + corpid = data.get('corpid') + QcWechatbizeventAddcontact.objects.update_or_create( + userid=userid, + externaluserid=externaluserid, + corpid=corpid, + defaults={ + **data, + 'isdelete': QcWechatbizeventAddcontactIsDeleteChoices.NOT_DELETE, + 'deletetime': None, + 'ctime': datetime.now(), + } + ) + qrcodeid = data.get('qrcodeid') + if qrcodeid: + JQRQrcodeCallbackPubSub.publish({ + 'qrcodeid': qrcodeid, + 'userid': userid, + 'externaluserid': externaluserid, + 'corpinfo': corpinfo, + 'handler': f'{qrcode_channel_handler.__module__}.{qrcode_channel_handler.__name__}' + }) + # 修复客户关系 + edit_add_contact(data, corpinfo, *args, **kwargs) + # # 转化外部用户Id + # WS.transfer_external_userid_to_vid(corpid, userid, externaluserid) + # 发送新客欢迎 + hook_user = JqrHookUser.objects.filter(corpid=corpid, userid=userid).first() + if hook_user is not None: + # utime 是否在 9 分钟内 + now = datetime.now() + nine_minute_ago = now - timedelta(minutes=9) + uid = hook_user.uid + createtime = data.get('createtime') + rc = SimpleLock(f'{corpid}:{userid}:{externaluserid}:{createtime}') + success = rc.try_lock(60 * 10) + if hook_user.utime > nine_minute_ago and hook_user.new_user and success: + # 发送消息 + send_new_user_msg(corpid, userid, external_userid=externaluserid, uid=uid) + except Exception as e: + logger.error(e) @shared_task(name='edit_add_contact', queue='contact') def edit_add_contact(data, corpinfo, *args, **kwargs): - # 更新 关系表 - externaluserid = data.get('externaluserid') - corpid = corpinfo.get('corpid') - appsecret = corpinfo.get('appsecret') - wechat_worker = WechatWorkerUtil(corpid, appsecret) - cursor = '' - while cursor is not None: - success, data = wechat_worker.get_external_contact(externaluserid, cursor=cursor) - if not success: - logger.error(f'获取外部联系人信息失败,{data}') - return - (external_contact, follow_user, cursor) = data - JqrExternalUser.objects.update_or_create( - corpid=corpid, - external_userid=externaluserid, - defaults={ - **external_contact, - 'addtype': JqrAddTypeChoices.EVENT_CALLBACK, - } - ) - for follow_info in follow_user: - userid = follow_info.get('userid') - follow_info['tags'] = [tag.get('tag_id') for tag in follow_info.get('tags', [])] - JqrExternalFollowUser.objects.update_or_create( - userid=userid, + try: + # 更新 关系表 + externaluserid = data.get('externaluserid') + corpid = corpinfo.get('corpid') + appsecret = corpinfo.get('appsecret') + wechat_worker = WechatWorkerUtil(corpid, appsecret) + cursor = '' + while cursor is not None: + success, data = wechat_worker.get_external_contact(externaluserid, cursor=cursor) + if not success: + logger.error(f'获取外部联系人信息失败,{data}') + return + (external_contact, follow_user, cursor) = data + JqrExternalUser.objects.update_or_create( corpid=corpid, external_userid=externaluserid, defaults={ - **follow_info, + **external_contact, 'addtype': JqrAddTypeChoices.EVENT_CALLBACK, - 'deletetype': 0, - 'dtime': None } ) + for follow_info in follow_user: + userid = follow_info.get('userid') + follow_info['tags'] = [tag.get('tag_id') for tag in follow_info.get('tags', [])] + JqrExternalFollowUser.objects.update_or_create( + userid=userid, + corpid=corpid, + external_userid=externaluserid, + defaults={ + **follow_info, + 'addtype': JqrAddTypeChoices.EVENT_CALLBACK, + 'deletetype': 0, + 'dtime': None + } + ) + except Exception as e: + logger.error(e) def edit_add_contact_by_channel(data, corpinfo, *args, **kwargs):