CRM - 销售与客户
一、销售与客户 - 表结构
---公共客户(公共资源)
1、没有报名
2、3天没有跟进
3、15天没有成单
客户分布表
龙泰 男 yuan 2018-5-1 3天未跟进
龙泰 男 三江 2018-5-5 15天未成单
龙泰 男 暴雨 2018-5-21 正在跟进
---我的客户(抢单)
crontab:
2018-5-15 12:00 龙泰 男 三江 2018-5-15 正在跟进
2018-5-16 0:0
2018-5-17 0:0
2018-5-18 0:0
2018-5-19 0:0 龙泰 男 三江 2018-5-19 3天未跟进
key: CustomerDistrbute为什么创建 ,为什么不能直接用Customer
因为:销售可以查看,自己的客户是否已过期,是否正在跟进,月底可以算业绩!
不能说没谈成,就没有业绩!!
一过期,就改了。定时脚本来完成!!
linux 固定时间,执行脚本 os 去做,
每天00:00去监测!
隔半天或隔一天,脚本每天凌晨监测一遍过期就放到公共客户。
新增客户分布表:
class CustomerDistrbute(models.Model): customer = models.ForeignKey("Customer", related_name="customers") consultant = models.ForeignKey(verbose_name="课程顾问", to="UserInfo", limit_choices_to={"depart_id":1001}) date = models.DateField() status_choices = ( (1, '正在跟进'), (2, '已报名'), (3, '三天未跟进'), (4, '15天未成单'), ) status = models.IntegerField(choices=status_choices, default=1) meno = models.CharField(max_length=255) def __str__(self): return self.customer.name + ":" + self.consultant.name
新的表结构
二、公共客户
知识点
1. 新增url
temp.append(url(r'^public/', self.public_customer))
2. datetime.timedelta ( 时间 + - )
datetime.datetime datetime.date datetime.time datetime.timedelta(days=7) now = datetime.datetime.now() delta_day3 = datetime.timedelta(days=3) delta_day15 = datetime.timedelta(days=15)
3. 未报名且3天未跟进或者15天未成单
# 3天未跟进 now - last_consult_date > 3 --> last_consult_date < now - 3 # 15天未成单 now - recv_date > 15 --> recv_date < now - 15 Q查询 last_consult_date__lt recv_date__lt customer_list = Customer.objects.filter( Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2)
4. exclude(排除)
# 不应该让之前的课程顾问 再看到这个已经放到公共名单的人了 user_id = 3 customer_list = Customer.objects.filter( Q(last_consult_date__lt=now - delta_day3) | Q(recv_date__lt=now - delta_day15),
status=2).exclude(consultant=user_id)
5. customer_list.query( sql 语句 )
# print(customer_list.query) """ SELECT "crm_customer"."id", "crm_customer"."qq", "crm_customer"."name", "crm_customer"."gender", "crm_customer"."education", "crm_customer"."graduation_school", "crm_customer"."major", "crm_customer"."experience", "crm_customer"."work_status", "crm_customer"."company", "crm_customer"."salary", "crm_customer"."source", "crm_customer"."referral_from_id", "crm_customer"."status", "crm_customer"."consultant_id", "crm_customer"."date", "crm_customer"."recv_date", "crm_customer"."last_consult_date" FROM "crm_customer" WHERE (("crm_customer"."last_consult_date" < 2018-06-24 OR "crm_customer"."recv_date" < 2018-06-12) AND "crm_customer"."status" = 2) """
def public_customer(self, request): # 未报名且3天未跟进或者15天未成单 from django.db.models import Q import datetime """ datetime.datetime datetime.date datetime.time datetime.timedelta(days=7) """ now = datetime.datetime.now() delta_day3 = datetime.timedelta(days=3) delta_day15 = datetime.timedelta(days=15) # 3天未跟进 now - last_consult_date > 3 --> last_consult_date < now - 3 # 15天未成单 now - recv_date > 15 --> recv_date < now - 15 # customer_list = Customer.objects.filter( # Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2) # 不应该让之前的课程顾问 再看到这个人已经放到公共名单的人了 user_id = 3 customer_list = Customer.objects.filter( Q(last_consult_date__lt=now - delta_day3) | Q(recv_date__lt=now - delta_day15), status=2).exclude(consultant=user_id) # print(customer_list.query) """ SELECT "crm_customer"."id", "crm_customer"."qq", "crm_customer"."name", "crm_customer"."gender", "crm_customer"."education", "crm_customer"."graduation_school", "crm_customer"."major", "crm_customer"."experience", "crm_customer"."work_status", "crm_customer"."company", "crm_customer"."salary", "crm_customer"."source", "crm_customer"."referral_from_id", "crm_customer"."status", "crm_customer"."consultant_id", "crm_customer"."date", "crm_customer"."recv_date", "crm_customer"."last_consult_date" FROM "crm_customer" WHERE (("crm_customer"."last_consult_date" < 2018-06-24 OR "crm_customer"."recv_date" < 2018-06-12) AND "crm_customer"."status" = 2) """ print("----->>:", customer_list) return render(request, 'public.html', locals())
------------------------
temp.append(url(r'^public/', self.public_customer))
public.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> </head> <body> <h3>公共客户</h3> <div class="container"> <div class="row"> <div class="col-md-6"> <table class="table table-bordered table-striped"> <thead> <tr> <th>ID</th> <th>姓名</th> <th>QQ</th> <th>课程顾问</th> <th>跟进详情</th> <th>确认跟进</th> </tr> </thead> <tbody> {% for customer in customer_list %} <tr> <td>{{ forloop.counter }}</td> <td>{{ customer.name }}</td> <td>{{ customer.qq }}</td> <td>{{ customer.consultant }}</td> <td><a href="/stark/crm/consultrecord/?customer={{ customer.pk }}">跟进记录</a></td> <td><a href="/stark/crm/customer/further/{{ customer.pk }}">确认跟进</a></td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> </body> </html>
三、确认跟进
知识点
1. 新增url
temp.append(url(r'^further/(\d+)', self.further))
2. 更改课程顾问和对应的时间
一定要先过滤;防止多个用户同时抢单,给了 最后一个抢单的人;先过滤之后再抢单,注意提示已经被跟进了。
ret = Customer.objects.filter(pk=customer_id).filter( Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2).update( consultant=user_id,last_consult_date = now,recv_date=now )
3. 创建一条客户分布表
为我的客户页面做准备
CustomerDistrbute.objects.create( customer_id=customer_id,consultant_id=user_id, date=now,status=1, )
temp.append(url(r'^further/(\d+)', self.further)) ------------------------------------------------------- def further(self, request,customer_id): """确认跟进""" user_id = 3 now = datetime.datetime.now() delta_day3 = datetime.timedelta(days=3) delta_day15 = datetime.timedelta(days=15) # 为该客户更改课程顾问 和对应得时间, ret = Customer.objects.filter(pk=customer_id).filter( Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2).update( consultant=user_id,last_consult_date = now,recv_date=now ) if not ret: return HttpResponse('已经被跟进了') CustomerDistrbute.objects.create( customer_id=customer_id,consultant_id=user_id, date=now,status=1, ) return HttpResponse('跟进成功')
四、我的客户
知识点
1. 新增url
temp.append(url(r'^mycustomer/', self.mycustomer))
2. 客户分布表查询
不能再 Customer表查询,这里查到的只是正在跟踪的客户信息
但是,之前跟踪过的客户,状态也要显示
customer_distrubute_list = CustomerDistrbute.objects.filter(consultant_id=user_id)
temp.append(url(r'^mycustomer/', self.mycustomer)) --------------------------------------------- def mycustomer(self, request): user_id = 3 customer_distrubute_list = CustomerDistrbute.objects.filter(consultant_id=user_id) return render(request,'mycustomer.html', locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>我的客户</h4> <ul> {% for customer_distrubute in customer_distrubute_list %} <li> {{ customer_distrubute.customer }} -----{{ customer_distrubute.date|date:'Y-m-d' }} -----{{ customer_distrubute.get_status_display }} </li> {% endfor %} </ul> </body> </html>
五、code
crm/stark.py
# -*- coding:utf-8 -*- from .models import * from stark.service.stark import site, ModelStark from django.utils.safestring import mark_safe from django.conf.urls import url from django.shortcuts import HttpResponse,reverse,redirect,render import datetime from django.db.models import Q class DepartmentConfig(ModelStark): list_display = ['title', 'code'] site.register(Department, DepartmentConfig) class UserInfoConfig(ModelStark): list_display = ["name", 'email', 'depart'] site.register(UserInfo, UserInfoConfig) class ClassListConfig(ModelStark): def display_classname(self,obj=None,header=False): if header: return "班级名称" return "%s(%s)"%(obj.course.name, obj.semester) list_display = [display_classname, 'tutor', 'teachers'] site.register(ClassList, ClassListConfig) class CustomerConfig(ModelStark): def display_course(self, obj=None, header=False): if header: return "咨询课程" temp = [] for course in obj.course.all(): temp.append("<a href='/stark/crm/customer/cancel_course/%s/%s' style='border:1px solid #369; padding:3px 6px;'><span>%s</span></a> "%(obj.pk,course.pk,course.name)) return mark_safe("".join(temp)) def cancel_course(self, request, customer_id, course_id): customer_obj = Customer.objects.filter(pk=customer_id).first() customer_obj.course.remove(course_id) return redirect(self.get_list_url()) # 重定向到当前表得查看页面 def public_customer(self, request): # 未报名且3天未跟进或者15天未成单 from django.db.models import Q import datetime """ datetime.datetime datetime.date datetime.time datetime.timedelta(days=7) """ now = datetime.datetime.now() delta_day3 = datetime.timedelta(days=3) delta_day15 = datetime.timedelta(days=15) # 3天未跟进 now - last_consult_date > 3 --> last_consult_date < now - 3 # 15天未成单 now - recv_date > 15 --> recv_date < now - 15 # customer_list = Customer.objects.filter( # Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2) # 不应该让之前的课程顾问 再看到这个已经放到公共名单的人了 user_id = 3 customer_list = Customer.objects.filter( Q(last_consult_date__lt=now - delta_day3) | Q(recv_date__lt=now - delta_day15), status=2).exclude(consultant=user_id) # print(customer_list.query) """ SELECT "crm_customer"."id", "crm_customer"."qq", "crm_customer"."name", "crm_customer"."gender", "crm_customer"."education", "crm_customer"."graduation_school", "crm_customer"."major", "crm_customer"."experience", "crm_customer"."work_status", "crm_customer"."company", "crm_customer"."salary", "crm_customer"."source", "crm_customer"."referral_from_id", "crm_customer"."status", "crm_customer"."consultant_id", "crm_customer"."date", "crm_customer"."recv_date", "crm_customer"."last_consult_date" FROM "crm_customer" WHERE (("crm_customer"."last_consult_date" < 2018-06-24 OR "crm_customer"."recv_date" < 2018-06-12) AND "crm_customer"."status" = 2) """ print("----->>:", customer_list) return render(request, 'public.html', locals()) def further(self, request,customer_id): """确认跟进""" user_id = 3 now = datetime.datetime.now() delta_day3 = datetime.timedelta(days=3) delta_day15 = datetime.timedelta(days=15) # 为该客户更改课程顾问 和对应得时间, ret = Customer.objects.filter(pk=customer_id).filter( Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2).update( consultant=user_id,last_consult_date = now,recv_date=now ) if not ret: return HttpResponse('已经被跟进了') CustomerDistrbute.objects.create( customer_id=customer_id,consultant_id=user_id, date=now,status=1, ) return HttpResponse('跟进成功') def mycustomer(self, request): user_id = 3 customer_distrubute_list = CustomerDistrbute.objects.filter(consultant_id=user_id) return render(request,'mycustomer.html', locals()) def extra_url(self): temp = [] temp.append(url(r'^cancel_course/(\d+)/(\d+)', self.cancel_course)) temp.append(url(r'^public/', self.public_customer)) temp.append(url(r'^further/(\d+)', self.further)) temp.append(url(r'^mycustomer/', self.mycustomer)) return temp list_display = ["name", "gender",display_course ,"consultant"] site.register(Customer, CustomerConfig) class ConsultRecordConfig(ModelStark): list_display = ["customer", 'consultant','date','note'] site.register(ConsultRecord, ConsultRecordConfig) from django.http import JsonResponse class StudentConfig(ModelStark): def score_view(self,request,sid): if request.is_ajax(): # print(request.GET) cid = request.GET.get('cid') sid = request.GET.get('sid') # 跨表查 study_record_list = StudyRecord.objects.filter(student=sid,course_record__class_obj=cid) data_list = [] for study_record in study_record_list: day_num = study_record.course_record.day_num data_list.append(["day%s"%day_num,study_record.score]) # # [['day94', 85], ['day95', 85], ['day96', -1]] return JsonResponse(data_list,safe=False) else: student = Student.objects.filter(pk=sid).first() class_list = student.class_list.all() return render(request,'score_view.html', locals()) def extra_url(self): temp = [] temp.append(url(r"^score_view/(\d+)",self.score_view)) return temp def score_show(self, obj=None, header=False): if header: return "查看成绩" return mark_safe("<a href='score_view/%s'>查看成绩</a>"%obj.pk) list_display = ['customer','class_list',score_show] list_display_links = ['customer'] site.register(Student,StudentConfig) class CourseRecordConfig(ModelStark): def score(self,request, course_record_id): if request.method == "POST": print('post::::', request.POST) """ <QueryDict: {'csrfmiddlewaretoken': ['muIrf7pwbxIueSJcKADRlZEGVbzzRZOaiGVkBV8DGYC2V9gmxZtyZgujddFtTojk'], 'score_33': ['100'], 'homework_note_33': ['很好'], 'score_34': ['85'], 'homework_note_34': ['棒'], 'score_35': ['60'], 'homework_note_35': ['None']}> """ data = {} # data={"33":{"score":100,"homework_note":'xxx'},} for key,value in request.POST.items(): if key == "csrfmiddlewaretoken":continue field, pk = key.rsplit('_', 1) if pk in data: data[pk][field] = value else: data[pk] = {field:value} print("data-->",data) """ {'33': {'score': '90', 'homework_note': '很好'}, '34': {'score': '80', 'homework_note': '帮帮哒'}, '35': {'score': '50', 'homework_note': '没问题'}} """ for pk,update_data in data.items(): StudyRecord.objects.filter(pk=pk).update(**update_data) return redirect(request.path) else: study_record_list = StudyRecord.objects.filter(course_record__id=course_record_id) score_choices = StudyRecord.score_choices return render(request,'score.html',locals()) def extra_url(self): temp = [] temp.append(url(r'^record_score/(\d+)', self.score)) return temp def record(self, obj=None, header=False): if header: return "学习记录" return mark_safe("<a href='/stark/crm/studyrecord/?course_record=%s'>记录</a>"%(obj.pk)) def record_score(self, obj=None, header=False): if header: return "录入成绩" return mark_safe("<a href='record_score/%s'>录入成绩</a>"%obj.pk) list_display = ["class_obj", 'day_num', "teacher", record, record_score ] def patch_studyrecord(self,request,queryset): # print('queryset:--》',queryset) temp = [] for course_record in queryset: # 与course_record 关联得班级对应得学生 students_list = Student.objects.filter(class_list__id = course_record.class_obj.pk) for student in students_list: student_obj = StudyRecord(course_record=course_record,student=student) temp.append(student_obj) StudyRecord.objects.bulk_create(temp) actions = [patch_studyrecord] patch_studyrecord.short_description = "批量生成学习记录" site.register(CourseRecord,CourseRecordConfig) class StudyRecordConfig(ModelStark): list_display = ['student','course_record','record','score'] def patch_late(self, request, queryset): queryset.update(record="late") patch_late.short_description = "迟到" actions = [patch_late] site.register(StudyRecord,StudyRecordConfig) site.register(Course) site.register(School) class CustomerDistrbuteConfig(ModelStark): list_display = ["customer",'consultant','date','status'] site.register(CustomerDistrbute,CustomerDistrbuteConfig)