CRM - 销售与客户

时间:2023-03-09 21:36:07
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

新的表结构

CRM - 销售与客户


二、公共客户

CRM - 销售与客户

知识点

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>

public.html

三、确认跟进

CRM - 销售与客户

知识点

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('跟进成功')

四、我的客户

CRM - 销售与客户

知识点

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>

mycustomer.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>&nbsp;"%(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)

stark.py