1、销售与客户的表结构

1、公共客户与我的客户

---公共客户(公共资源)
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

2、思考

因为:销售可以查看,自己的客户是否已过期,是否正在跟进,月底可以算业绩!
不能说没谈成,就没有业绩!!

我的客户与公共用户不能冲突!

我的客户要一直存在,月末要进行绩效统计,他的状态可以是,正在跟进,3天未跟进

一过期,就改了。linux定时脚本来完成!!
linux 固定时间,执行脚本 os 去做,
每天00:00去监测! 隔半天或隔一天,脚本每天凌晨监测一遍过期就放到公共客户。

刷新状态,或者把过期的用户移动到公共客户池子

可以通过,定时脚本,每天0:0进行

3、添加新的表

class CustomerDistrbute(models.Model):
customer = models.ForeignKey("Customer", related_name="customers",on_delete=True)
consultant = models.ForeignKey(verbose_name="课程顾问", to="UserInfo", limit_choices_to={"depart_id": 1001},on_delete=True)
date = models.DateField()
status = (
(1, "正在跟进"),
(2, "已报名"),
(3, "三天未跟进"),
(4, "15天未成单"),
)
status = models.IntegerField(choices=status, default=1) memo = models.CharField(max_length=255) def __str__(self):
return self.customer.name+":"+self.consultant.name

4、新的表结构

2、公共客户池

class CusotmerConfig(ModelStark):

    def public_customer(self,request):
"""公共客户"""
# 未报名 且3天未跟进或者15天未成单 import datetime
now =datetime.datetime.now()
print(now)
'''
datetime.datetime
datetime.time
datetime.date
datetime.timedelta(days=7)
''' # 3天未跟进 now - last_consult_date > 3 ----> last_consult_date < now-3
# 15天未成单 now - recv_date > 3 ----> recv_date < now-15
delta_day3 = datetime.timedelta(days=3)
delta_day15 = datetime.timedelta(days=15) from django.db.models import Q # Customer.objects.filter(status=2,last_consult_date__lt=now-3)
# customer_list = Customer.objects.filter(Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2) # 过滤掉 我的客户
user_id = 2
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('public_customer_list',customer_list) return render(request,'public.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))
return temp site.register(Customer, CusotmerConfig)

1、添加public的url

    def extra_url(self):
temp = []
temp.append(url(r"cancel_course/(\d+)/(\d+)", self.cancel_course))
temp.append(url(r"public/", self.public_customer))
return temp

2、 datetime.timedelta ( 时间 + - )

        import datetime
now =datetime.datetime.now()
print(now)
'''
datetime.datetime
datetime.time
datetime.date
datetime.timedelta(days=7)
''' # 3天未跟进 now - last_consult_date > 3 ----> last_consult_date < now-3
# 15天未成单 now - recv_date > 3 ----> recv_date < now-15
delta_day3 = datetime.timedelta(days=3)
delta_day15 = datetime.timedelta(days=15)

3、未报名 且3天未跟进或者15天未成单

 Q查询 last_consult_date__lt recv_date__lt
        from django.db.models import Q
# Customer.objects.filter(status=2,last_consult_date__lt=now-3)
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 = 2
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) """

6、跳转标签

                            <td><a href="/stark/crm/consultrecord/?customer={{ customer.pk }}">跟进记录</a></td>
<td><a href="/stark/crm/customer/further/{{ customer.pk }}">是</a></td>

7、public.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
<script src="/static/js/jquery-1.12.4.min.js"></script>
</head>
<body>
<h3>公共客户</h3>
<div class="container">
<div class="row">
<div class="col-md-9 col-md-offset-1">
<form action="" method="post">
{% csrf_token %}
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>QQ</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><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>
</form>
</div> </div>
</div>
</body>
</html>

3、确认跟进

  

url层

    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))
return temp

view层

    def further(self,request,customer_id):
user_id = 2 # request.session.get("user_id") import datetime
now =datetime.datetime.now()
delta_day3 = datetime.timedelta(days=3)
delta_day15 = datetime.timedelta(days=15)
from django.db.models import Q # 更改客户的课程顾问,和相应的时间
# Customer.objects.filter(pk=customer_id).update(consultant=user_id,last_consult_date=now,recv_date=now)
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

    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))
return temp

2、改客户的课程顾问,和相应的时间

未报名 且3天未跟进或者15天未成单

一定要先过滤;防止多个用户同时抢单,给了 最后一个抢单的人;先过滤之后再抢单,注意提示已经被跟进了。

        # 更改客户的课程顾问,和相应的时间
# Customer.objects.filter(pk=customer_id).update(consultant=user_id,last_consult_date=now,recv_date=now)
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('已经被跟进了') return HttpResponse('跟进成功')

3、客户跟进表的数据

为我的客户页面做准备

        CustomerDistrbute.objects.create(customer_id=customer_id,consultant_id=user_id,date=now,status=1)

4、我的客户

1、新增url

        temp.append(url(r"mycustomer/", self.mycustomer))

2. 客户分布表查询

  不能再 Customer表查询,这里查到的只是正在跟踪的客户信息

  但是,之前跟踪过的客户,状态也要显示

    def mycustomer(self,request):
user_id = 2
customer_distrbute_list = CustomerDistrbute.objects.filter(consultant=user_id)
print('customer_distrbute_list',customer_distrbute_list)
return render(request,'mycustomer.html',locals())

3、mycustomer.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
<script src="/static/js/jquery-1.12.4.min.js"></script>
</head>
<body>
<h3>我的客户</h3>
<div class="container">
<div class="row">
<div class="col-md-9 col-md-offset-1">
<form action="" method="post">
{% csrf_token %}
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>姓名</th>
<th>跟进日期</th>
<th>跟进详情</th>
</tr>
</thead>
{% for customer_distrbute in customer_distrbute_list %}
<tr>
<td>{{ customer_distrbute.customer }}</td>
<td>{{ customer_distrbute.date }}</td>
<td>{{ customer_distrbute.get_status_display }}</td>
</tr> {% endfor %} <tbody> </tbody>
</table>
</form>
</div> </div>
</div>
</body>
</html>

4、crontab定时脚本

5、code

crm/stark.py

# by luffycity.com

from stark.service.stark import site, ModelStark
from django.http import JsonResponse
from .models import * from django.utils.safestring import mark_safe
from django.conf.urls import url from django.shortcuts import HttpResponse, redirect, render site.register(School) class UserConfig(ModelStark):
list_display = ["name", "email", "depart"] site.register(UserInfo, UserConfig) class ClassConfig(ModelStark):
def display_classname(self, obj=None, header=False):
if header:
return "班级名称"
class_name = "%s(%s)" % (obj.course.name, str(obj.semester))
return class_name list_display = [display_classname, "tutor", "teachers"] site.register(ClassList, ClassConfig) class CusotmerConfig(ModelStark):
def display_gender(self, obj=None, header=False):
if header:
return "性别"
return obj.get_gender_display() def display_course(self, obj=None, header=False):
if header:
return "咨询课程"
temp = []
for course in obj.course.all():
s = "<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,)
temp.append(s)
return mark_safe("".join(temp)) # list_display = ["name",'gender','course',"consultant",]
list_display = ["name", display_gender, display_course, "consultant", ] def cancel_course(self, request, customer_id, course_id):
print(customer_id, course_id) obj = Customer.objects.filter(pk=customer_id).first()
obj.course.remove(course_id)
return redirect(self.get_list_url()) def public_customer(self,request):
"""公共客户"""
# 未报名 且3天未跟进或者15天未成单 import datetime
now =datetime.datetime.now()
print(now)
'''
datetime.datetime
datetime.time
datetime.date
datetime.timedelta(days=7)
''' # 3天未跟进 now - last_consult_date > 3 ----> last_consult_date < now-3
# 15天未成单 now - recv_date > 3 ----> recv_date < now-15
delta_day3 = datetime.timedelta(days=3)
delta_day15 = datetime.timedelta(days=15) from django.db.models import Q # Customer.objects.filter(status=2,last_consult_date__lt=now-3)
# customer_list = Customer.objects.filter(Q(last_consult_date__lt=now-delta_day3)|Q(recv_date__lt=now-delta_day15),status=2) # 过滤掉 我的客户
user_id = 2
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)
print('public_customer_list',customer_list) return render(request,'public.html',locals()) def further(self,request,customer_id):
user_id = 2 # request.session.get("user_id") import datetime
now =datetime.datetime.now()
delta_day3 = datetime.timedelta(days=3)
delta_day15 = datetime.timedelta(days=15)
from django.db.models import Q # 更改客户的课程顾问,和相应的时间
# Customer.objects.filter(pk=customer_id).update(consultant=user_id,last_consult_date=now,recv_date=now)
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 = 2
customer_distrbute_list = CustomerDistrbute.objects.filter(consultant=user_id)
print('customer_distrbute_list',customer_distrbute_list)
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 site.register(Customer, CusotmerConfig) site.register(Department)
site.register(Course) class ConsultConfig(ModelStark):
list_display = ['customer', 'consultant', 'date', 'note'] site.register(ConsultRecord, ConsultConfig) class CourseRecordConfig(ModelStark):
def score(self, request, course_record_id):
"""录入成绩view"""
study_record_list = StudyRecord.objects.filter(course_record=course_record_id)
print(study_record_list)
score_choices = StudyRecord.score_choices
if request.method == "POST":
print(request.POST) # <QueryDict: 'score_4': ['100'], 'homeword_note_4': ['33']}> data = {} # dic = {1:{'homework_note':'good','score':'90'},2:{'homework_note':'nonono','score':'80'},} 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) for pk, val in data.items():
StudyRecord.objects.filter(pk=pk).update(**val) '''
# 方式1
if field == 'score':
StudyRecord.objects.filter(pk=pk).update(score=value)
else:
StudyRecord.objects.filter(pk=pk).update(homework_note=value.strip())
''' return redirect(request.path) # 跳转到当前url return render(request, 'score.html', locals()) def extra_url(self):
"""录入成绩url"""
temp = []
temp.append(url('record_score/(\d+)', self.score))
return temp def record_score(self, obj=None, header=False):
"""录入成绩a标签"""
if header:
return "录入成绩"
return mark_safe("<a href='record_score/%s'>录入成绩</a>" % (obj.pk)) def record(self, obj=None, header=False):
if header:
return '学习记录'
return mark_safe("<a href='/stark/crm/studyrecord/?course_record=%s'>记录</a>" % (obj.pk)) list_display = ['class_obj', 'day_num', 'teacher', record, record_score] def patch_studyrecord(self, request, queryset):
print(queryset) # <QuerySet [<CourseRecord: python基础班(9期) day11>]>
temp = []
for course_record in queryset:
student_list = Student.objects.filter(class_list=course_record.class_obj.pk)
for student in student_list:
obj = StudyRecord(student=student, course_record=course_record)
temp.append(obj) StudyRecord.objects.bulk_create(temp) # 批量生成数据 patch_studyrecord.short_description = '批量生成学习记录'
actions = [patch_studyrecord, ] site.register(CourseRecord, CourseRecordConfig) class StudyRecordConfig(ModelStark):
def display_record(self, obj=None, header=False):
if header:
return "记录"
return obj.get_record_display() def display_score(self, obj=None, header=False):
if header:
return "成绩"
return obj.get_score_display() list_display = ['student', 'course_record', display_record, display_score] def patch_late(self, request, queryset):
queryset.update(record='late') patch_late.short_description = '迟到'
actions = [patch_late] site.register(StudyRecord, StudyRecordConfig) class StudentConfig(ModelStark):
def score_view(self, request, stu_id):
"""查看成绩 view"""
if request.is_ajax():
cid = request.GET.get('cid')
sid = request.GET.get('sid') print(cid,sid)
study_record_list = StudyRecord.objects.filter(student=sid,course_record__class_obj=cid) print('study_record_list',study_record_list) # 方案1:构造数据 # [['day11', 85], ['day12', 90]]
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]) print('data_list',data_list) #方案2:构造数据 dic = {day:[day11,day12],score:[85,90]}
dic = {'day':[],'score':[]}
for study_record in study_record_list:
day_num = study_record.course_record.day_num
dic['day'].append('day%s'%day_num)
dic['score'].append(study_record.score)
print(dic)
print(dic['day'])
print(dic['score']) return JsonResponse(dic,safe=False) else:
student = Student.objects.filter(pk=stu_id).first()
class_list = student.class_list.all()
return render(request, 'score_view.html', locals()) def extra_url(self):
"""查看成绩url"""
temp = []
temp.append(url(r"score_view/(\d+)", self.score_view))
return temp def score_show(self, obj=None, header=False):
"""查看成绩 a标签"""
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)

stark/service/stark

# by luffycity.com
from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect
from django.urls import reverse
from django.db.models import Q
from django.utils.safestring import mark_safe from stark.utils.page import Pagination
from django.db.models.fields.related import ManyToManyField,ForeignKey class ShowList(object):
def __init__(self,config,data_list,request):
self.config=config
self.data_list=data_list
self.request=request
#分页
data_count=self.data_list.count()
current_page=int(self.request.GET.get("page",1))
base_path=self.request.path self.pagination=Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=10, pager_count=11, )
self.page_data=self.data_list[self.pagination.start:self.pagination.end] # actions
self.actions=self.config.new_actions() # [patch_init,] def get_filter_linktags(self):
print("list_filter:",self.config.list_filter)
link_dic={}
import copy for filter_field in self.config.list_filter: # ["title","publish","authors",]
params = copy.deepcopy(self.request.GET) cid=self.request.GET.get(filter_field,0) print("filter_field",filter_field) # "publish"
filter_field_obj=self.config.model._meta.get_field(filter_field)
print("filter_field_obj",filter_field_obj)
print(type(filter_field_obj))
from django.db.models.fields.related import ForeignKey
from django.db.models.fields.related import ManyToManyField
print("rel======...",filter_field_obj.rel) if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
data_list=filter_field_obj.rel.to.objects.all()# 【publish1,publish2...】
else:
data_list=self.config.model.objects.all().values("pk",filter_field)
print("data_list",data_list) temp=[]
# 处理 全部标签
if params.get(filter_field):
del params[filter_field]
temp.append("<a href='?%s'>全部</a>"%params.urlencode())
else:
temp.append("<a class='active' href='#'>全部</a>") # 处理 数据标签
for obj in data_list:
if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
pk=obj.pk
text=str(obj)
params[filter_field] = pk
else: # data_list= [{"pk":1,"title":"go"},....]
print("========")
pk=obj.get("pk")
text=obj.get(filter_field)
params[filter_field] =text _url=params.urlencode()
if cid==str(pk) or cid==text:
link_tag="<a class='active' href='?%s'>%s</a>"%(_url,text)
else:
link_tag = "<a href='?%s'>%s</a>" % (_url, text)
temp.append(link_tag) link_dic[filter_field]=temp return link_dic def get_action_list(self):
temp=[]
for action in self.actions:
temp.append({
"name":action.__name__,
"desc":action.short_description
}) # [{"name":""patch_init,"desc":"批量初始化"}] return temp def get_header(self):
# 构建表头
header_list = []
print("header",
self.config.new_list_play()) # [checkbox,"pk","name","age",edit ,deletes] 【checkbox ,"__str__", edit ,deletes】 for field in self.config.new_list_play(): if callable(field):
# header_list.append(field.__name__)
val = field(self.config, header=True)
header_list.append(val) else:
if field == "__str__":
header_list.append(self.config.model._meta.model_name.upper())
else:
# header_list.append(field)
val = self.config.model._meta.get_field(field).verbose_name
header_list.append(val)
return header_list def get_body(self):
# 构建表单数据
new_data_list = []
for obj in self.page_data:
temp = []
for filed in self.config.new_list_play(): # ["__str__",] ["pk","name","age",edit]
if callable(filed):
print("obj-----:",obj)
val = filed(self.config, obj)
else:
try:
field_obj=self.config.model._meta.get_field(filed)
if isinstance(field_obj,ManyToManyField):
ret = getattr(obj,filed).all()
t=[]
for mobj in ret:
t.append(str(mobj))
val=",".join(t)
else:
print("+++++>>",field_obj.choices)
if field_obj.choices:
val = getattr(obj,'get_'+filed+'_display')
else:
val = getattr(obj, filed)
if filed in self.config.list_display_links:
# "app01/userinfo/(\d+)/change"
_url = self.config.get_change_url(obj)
val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) except Exception as e:
val = getattr(obj, filed)
temp.append(val)
new_data_list.append(temp)
return new_data_list '''
[
[1,"alex",12],
[1,"alex",12],
[1,"alex",12],
[1,"alex",12], ] ''' class ModelStark(object): list_display=["__str__",]
list_display_links=[]
modelform_class=None
search_fields=[]
actions = []
list_filter=[] def patch_delete(self, request, queryset): queryset.delete() patch_delete.short_description = "批量删除" def __init__(self,model,site):
self.model=model
self.site=site # 删除 编辑,复选框
def edit(self,obj=None,header=False):
if header:
return "操作"
#return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk)
_url=self.get_change_url(obj) return mark_safe("<a href='%s'>编辑</a>"%_url) def deletes(self,obj=None,header=False):
if header:
return "操作"
# return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk) _url=self.get_delete_url(obj) return mark_safe("<a href='%s'>删除</a>" % _url) def checkbox(self,obj=None,header=False):
if header:
return mark_safe('<input id="choice" type="checkbox">') return mark_safe('<input class="choice_item" type="checkbox" name="selected_pk" value="%s">'%obj.pk) def get_modelform_class(self): if not self.modelform_class:
from django.forms import ModelForm
from django.forms import widgets as wid
class ModelFormDemo(ModelForm):
class Meta:
model = self.model
fields = "__all__"
labels={
""
}
return ModelFormDemo
else:
return self.modelform_class def get_new_form(self,form): for bfield in form:
from django.forms.boundfield import BoundField
print(bfield.field) # 字段对象
print("name",bfield.name) # 字段名(字符串)
print(type(bfield.field)) # 字段类型
from django.forms.models import ModelChoiceField
if isinstance(bfield.field,ModelChoiceField):
bfield.is_pop=True print("=======>",bfield.field.queryset.model) # 一对多或者多对多字段的关联模型表 related_model_name=bfield.field.queryset.model._meta.model_name
related_app_label=bfield.field.queryset.model._meta.app_label _url=reverse("%s_%s_add"%(related_app_label,related_model_name))
bfield.url=_url+"?pop_res_id=id_%s"%bfield.name return form def add_view(self, request):
ModelFormDemo = self.get_modelform_class()
form = ModelFormDemo() form=self.get_new_form(form) if request.method=="POST":
form = ModelFormDemo(request.POST)
if form.is_valid():
obj=form.save() pop_res_id=request.GET.get("pop_res_id") if pop_res_id:
res ={"pk":obj.pk,"text":str(obj),"pop_res_id":pop_res_id}
import json
return render(request, "pop.html", {"res":res}) else:
return redirect(self.get_list_url()) return render(request, "add_view.html", locals()) def delete_view(self, request, id):
url = self.get_list_url()
if request.method=="POST":
self.model.objects.filter(pk=id).delete()
return redirect(url) return render(request, "delete_view.html", locals()) def change_view(self, request, id):
ModelFormDemo = self.get_modelform_class()
print("=====id",id)
edit_obj = self.model.objects.filter(pk=id).first() if request.method=="POST":
form = ModelFormDemo(request.POST,instance=edit_obj)
if form.is_valid():
form.save()
return redirect(self.get_list_url()) return render(request, "add_view.html", locals()) print("***********",edit_obj)
form = ModelFormDemo(instance=edit_obj)
form = self.get_new_form(form) return render(request, "change_view.html", locals()) def new_list_play(self):
temp=[]
temp.append(ModelStark.checkbox)
temp.extend(self.list_display)
if not self.list_display_links:
temp.append(ModelStark.edit)
temp.append(ModelStark.deletes)
return temp def new_actions(self):
temp=[]
temp.append(ModelStark.patch_delete)
temp.extend(self.actions) return temp def get_change_url(self,obj):
model_name = self.model._meta.model_name
app_label = self.model._meta.app_label
print("obj===========",obj)
_url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) return _url def get_delete_url(self, obj):
model_name = self.model._meta.model_name
app_label = self.model._meta.app_label _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,)) return _url def get_add_url(self): model_name = self.model._meta.model_name
app_label = self.model._meta.app_label _url = reverse("%s_%s_add" % (app_label, model_name)) return _url def get_list_url(self): model_name = self.model._meta.model_name
app_label = self.model._meta.app_label _url = reverse("%s_%s_list" % (app_label, model_name)) return _url def get_serach_conditon(self,request):
key_word = request.GET.get("q","")
self.key_word=key_word search_connection = Q()
if key_word:
# self.search_fields # ["title","price"]
search_connection.connector = "or"
for search_field in self.search_fields:
search_connection.children.append((search_field + "__contains", key_word))
return search_connection def get_filter_condition(self,request):
filter_condition=Q() for filter_field,val in request.GET.items(): # courserecord=2
# if filter_field in self.list_filter:
if filter_field != 'page':
filter_condition.children.append((filter_field,val)) return filter_condition def list_view(self, request):
if request.method=="POST": # action
print("POST:",request.POST)
action=request.POST.get("action") # patch_init
selected_pk=request.POST.getlist("selected_pk")
action_func=getattr(self,action)
queryset=self.model.objects.filter(pk__in=selected_pk)
ret=action_func(request,queryset) #return ret # 获取serach的Q对象
search_connection=self.get_serach_conditon(request) # 获取filter构建Q对象 filter_condition=self.get_filter_condition(request) # 筛选获取当前表所有数据
data_list=self.model.objects.all().filter(search_connection).filter(filter_condition) # 【obj1,obj2,....】 # 按这ShowList展示页面
showlist=ShowList(self,data_list,request) # 构建一个查看URL
add_url=self.get_add_url()
return render(request, "list_view.html", locals()) def extra_url(self): return [] def get_urls_2(self): temp = [] model_name=self.model._meta.model_name
app_label=self.model._meta.app_label temp.append(url(r"^add/", self.add_view,name="%s_%s_add"%(app_label,model_name)))
temp.append(url(r"^(\d+)/delete/", self.delete_view,name="%s_%s_delete"%(app_label,model_name)))
temp.append(url(r"^(\d+)/change/", self.change_view,name="%s_%s_change"%(app_label,model_name)))
temp.append(url(r"^$", self.list_view,name="%s_%s_list"%(app_label,model_name))) temp.extend(self.extra_url()) return temp @property
def urls_2(self):
print(self.model)
return self.get_urls_2(), None, None class StarkSite(object):
def __init__(self):
self._registry={} def register(self,model,stark_class=None):
if not stark_class:
stark_class=ModelStark self._registry[model] = stark_class(model, self) def get_urls(self):
temp=[]
for model,stark_class_obj in self._registry.items():
model_name=model._meta.model_name
app_label=model._meta.app_label
# 分发增删改查
temp.append(url(r"^%s/%s/"%(app_label,model_name),stark_class_obj.urls_2)) '''
url(r"^app01/userinfo/",UserConfig(Userinfo).urls_2),
url(r"^app01/book/",ModelStark(Book).urls_2), '''
return temp @property
def urls(self): return self.get_urls(),None,None site=StarkSite()

models.py

from django.db import models

# Create your models here.

class Department(models.Model):
"""
部门表
市场部 1000
销售 1001 """
title = models.CharField(verbose_name='部门名称', max_length=16)
code = models.IntegerField(verbose_name='部门编号', unique=True, null=False) def __str__(self):
return self.title class UserInfo(models.Model):
"""
员工表
""" name = models.CharField(verbose_name='员工姓名', max_length=16)
username = models.CharField(verbose_name='用户名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
email = models.EmailField(verbose_name='邮箱', max_length=64) depart = models.ForeignKey(verbose_name='部门', to="Department", to_field="code", on_delete=True) def __str__(self):
return self.name class Course(models.Model):
"""
课程表
如:
Linux基础
Linux架构师
Python自动化开发精英班
Python自动化开发架构师班
Python基础班
go基础班
"""
name = models.CharField(verbose_name='课程名称', max_length=32) def __str__(self):
return self.name class School(models.Model):
"""
校区表
如:
北京沙河校区
上海校区 """
title = models.CharField(verbose_name='校区名称', max_length=32) def __str__(self):
return self.title class ClassList(models.Model):
"""
班级表
如:
Python全栈 面授班 5期 10000 2017-11-11 2018-5-11
"""
school = models.ForeignKey(verbose_name='校区', to='School', on_delete=True)
course = models.ForeignKey(verbose_name='课程名称', to='Course', on_delete=True) semester = models.IntegerField(verbose_name="班级(期)")
price = models.IntegerField(verbose_name="学费")
start_date = models.DateField(verbose_name="开班日期")
graduate_date = models.DateField(verbose_name="结业日期", null=True, blank=True)
memo = models.CharField(verbose_name='说明', max_length=256, blank=True, null=True, ) # teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo',limit_choices_to={'depart_id__in':[1003,1004],})
teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo', related_name="abc",
limit_choices_to={"depart__in": [1002, 1005]})
tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo', related_name='classes',
limit_choices_to={"depart": 1001}, on_delete=True) def __str__(self):
return "{0}({1}期)".format(self.course.name, self.semester) class Customer(models.Model):
"""
客户表
"""
qq = models.CharField(verbose_name='qq', max_length=64, unique=True, help_text='QQ号必须唯一') name = models.CharField(verbose_name='学生姓名', max_length=16)
gender_choices = ((1, '男'), (2, '女'))
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices) education_choices = (
(1, '重点大学'),
(2, '普通本科'),
(3, '独立院校'),
(4, '民办本科'),
(5, '大专'),
(6, '民办专科'),
(7, '高中'),
(8, '其他')
)
education = models.IntegerField(verbose_name='学历', choices=education_choices, blank=True, null=True, )
graduation_school = models.CharField(verbose_name='毕业学校', max_length=64, blank=True, null=True)
major = models.CharField(verbose_name='所学专业', max_length=64, blank=True, null=True) experience_choices = [
(1, '在校生'),
(2, '应届毕业'),
(3, '半年以内'),
(4, '半年至一年'),
(5, '一年至三年'),
(6, '三年至五年'),
(7, '五年以上'),
]
experience = models.IntegerField(verbose_name='工作经验', blank=True, null=True, choices=experience_choices)
work_status_choices = [
(1, '在职'),
(2, '无业')
]
work_status = models.IntegerField(verbose_name="职业状态", choices=work_status_choices, default=1, blank=True,
null=True)
company = models.CharField(verbose_name="目前就职公司", max_length=64, blank=True, null=True)
salary = models.CharField(verbose_name="当前薪资", max_length=64, blank=True, null=True) source_choices = [
(1, "qq群"),
(2, "内部转介绍"),
(3, "官方网站"),
(4, "百度推广"),
(5, "360推广"),
(6, "搜狗推广"),
(7, "腾讯课堂"),
(8, "广点通"),
(9, "高校宣讲"),
(10, "渠道代理"),
(11, "51cto"),
(12, "智汇推"),
(13, "网盟"),
(14, "DSP"),
(15, "SEO"),
(16, "其它"),
]
source = models.SmallIntegerField('客户来源', choices=source_choices, default=1)
referral_from = models.ForeignKey(
'self',
blank=True,
null=True,
verbose_name="转介绍自学员",
help_text="若此客户是转介绍自内部学员,请在此处选择内部学员姓名",
related_name="internal_referral", on_delete=True
)
course = models.ManyToManyField(verbose_name="咨询课程", to="Course") status_choices = [
(1, "已报名"),
(2, "未报名")
]
status = models.IntegerField(
verbose_name="状态",
choices=status_choices,
default=2,
help_text=u"选择客户此时的状态"
) consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo', related_name='consultanter',
limit_choices_to={'depart_id': 1001}, on_delete=True) date = models.DateField(verbose_name="咨询日期", auto_now_add=True)
recv_date = models.DateField(verbose_name="当前课程顾问的接单日期", null=True)
last_consult_date = models.DateField(verbose_name="最后跟进日期", ) def __str__(self):
return "姓名:{0},QQ:{1}".format(self.name, self.qq, ) class ConsultRecord(models.Model):
"""
客户跟进记录
"""
customer = models.ForeignKey(verbose_name="所咨询客户", to='Customer', on_delete=True)
consultant = models.ForeignKey(verbose_name="跟踪人", to='UserInfo', on_delete=True)
date = models.DateField(verbose_name="跟进日期", auto_now_add=True)
note = models.TextField(verbose_name="跟进内容...") def __str__(self):
return self.customer.name + ":" + self.consultant.name class Student(models.Model):
"""
学生表(已报名)
"""
customer = models.OneToOneField(verbose_name='客户信息', to='Customer', on_delete=True) username = models.CharField(verbose_name='用户名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='紧急联系人') class_list = models.ManyToManyField(verbose_name="已报班级", to='ClassList', blank=True)
company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True)
location = models.CharField(max_length=64, verbose_name='所在区域', blank=True, null=True)
position = models.CharField(verbose_name='岗位', max_length=64, blank=True, null=True)
salary = models.IntegerField(verbose_name='薪资', blank=True, null=True)
welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True)
date = models.DateField(verbose_name='入职时间', help_text='格式yyyy-mm-dd', blank=True, null=True)
memo = models.CharField(verbose_name='备注', max_length=256, blank=True, null=True) def __str__(self):
return self.username class CourseRecord(models.Model):
"""
上课记录表
"""
class_obj = models.ForeignKey(verbose_name="班级", to="ClassList", on_delete=True)
day_num = models.IntegerField(verbose_name="节次", help_text=u"此处填写第几节课或第几天课程...,必须为数字")
teacher = models.ForeignKey(verbose_name="讲师", to='UserInfo', limit_choices_to={"depart_id__in": [1002, 1003]},
on_delete=True)
date = models.DateField(verbose_name="上课日期", auto_now_add=True) course_title = models.CharField(verbose_name='本节课程标题', max_length=64, blank=True, null=True)
course_memo = models.TextField(verbose_name='本节课程内容概要', blank=True, null=True)
has_homework = models.BooleanField(default=True, verbose_name="本节有作业")
homework_title = models.CharField(verbose_name='本节作业标题', max_length=64, blank=True, null=True)
homework_memo = models.TextField(verbose_name='作业描述', max_length=500, blank=True, null=True)
exam = models.TextField(verbose_name='踩分点', max_length=300, blank=True, null=True) def __str__(self):
return "{0} day{1}".format(self.class_obj, self.day_num) class StudyRecord(models.Model):
course_record = models.ForeignKey(verbose_name="第几天课程", to="CourseRecord", on_delete=True)
student = models.ForeignKey(verbose_name="学员", to='Student', on_delete=True)
record_choices = (('checked', "已签到"),
('vacate', "请假"),
('late', "迟到"),
('noshow', "缺勤"),
('leave_early', "早退"),
)
record = models.CharField("上课纪录", choices=record_choices, default="checked", max_length=64)
score_choices = ((100, 'A+'),
(90, 'A'),
(85, 'B+'),
(80, 'B'),
(70, 'B-'),
(60, 'C+'),
(50, 'C'),
(40, 'C-'),
(0, ' D'),
(-1, 'N/A'),
(-100, 'COPY'),
(-1000, 'FAIL'),
)
score = models.IntegerField("本节成绩", choices=score_choices, default=-1)
homework_note = models.CharField(verbose_name='作业评语', max_length=255, blank=True, null=True)
note = models.CharField(verbose_name="备注", max_length=255, blank=True, null=True) homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)
stu_memo = models.TextField(verbose_name='学员备注', blank=True, null=True)
date = models.DateTimeField(verbose_name='提交作业日期', auto_now_add=True) def __str__(self):
return "{0}-{1}".format(self.course_record, self.student) class CustomerDistrbute(models.Model):
customer = models.ForeignKey("Customer", related_name="customers",on_delete=True)
consultant = models.ForeignKey(verbose_name="课程顾问", to="UserInfo", limit_choices_to={"depart_id": 1001},on_delete=True)
date = models.DateField()
status = (
(1, "正在跟进"),
(2, "已报名"),
(3, "三天未跟进"),
(4, "15天未成单"),
)
status = models.IntegerField(choices=status, default=1) memo = models.CharField(max_length=255) def __str__(self):
return self.customer.name+":"+self.consultant.name

public.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
<script src="/static/js/jquery-1.12.4.min.js"></script>
</head>
<body>
<h3>公共客户</h3>
<div class="container">
<div class="row">
<div class="col-md-9 col-md-offset-1">
<form action="" method="post">
{% csrf_token %}
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>QQ</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><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>
</form>
</div> </div>
</div>
</body>
</html>

mycustomer.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
<script src="/static/js/jquery-1.12.4.min.js"></script>
</head>
<body>
<h3>我的客户</h3>
<div class="container">
<div class="row">
<div class="col-md-9 col-md-offset-1">
<form action="" method="post">
{% csrf_token %}
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>姓名</th>
<th>跟进日期</th>
<th>跟进详情</th>
</tr>
</thead>
{% for customer_distrbute in customer_distrbute_list %}
<tr>
<td>{{ customer_distrbute.customer }}</td>
<td>{{ customer_distrbute.date }}</td>
<td>{{ customer_distrbute.get_status_display }}</td>
</tr> {% endfor %} <tbody> </tbody>
</table>
</form>
</div> </div>
</div>
</body>
</html>

3 CRM 销售与客户 我的客户,公共客户池的更多相关文章

  1. 如何借助CRM销售管理系统提升业绩?

    与传统企业销售模式不同,现代企业在网络背书下,销售活动与网络密切相关.销售数据需要网络保存,销售渠道需要网络挖掘.在线的销售软件让销售活动起到了事半功倍的效果.CRM销售管理系统是企业必不可少的在线软 ...

  2. CRM - 销售与客户

    一.销售与客户 - 表结构 ---公共客户(公共资源) 1.没有报名 2.3天没有跟进 3.15天没有成单 客户分布表 龙泰 男 yuan 2018-5-1 3天未跟进 龙泰 男 三江 2018-5- ...

  3. CRM——销售与客户

    一.销售与客户——表结构 1.客户类型 (1)公共客户(公共资源) 必备条件:没有报名: 在必备条件满足的情况下,满足以下任意条件都是公共客户: 3天没有跟进:15天没有成单. (2)我的客户 原销售 ...

  4. 项目一:第七天 CRM 和bos系统实现定区关联客户,关联快递员. 通过CXF框架实现

    定区关联客户 需求:为了快递方便客户下订单(发快递),派快递员上门取件.  所以说需要让定区关联客户(知道客户属于哪个定区),定区跟快递员关系:多对多.知道让哪个快递员上门取件. 将CRM系统中,客户 ...

  5. ASP微信服务号H5客户登陆,且获取客户授权的用户基本信息

    ASP微信服务号H5客户登陆,且获取客户授权的用户基本信息是需要客户授权,下面讲解详细步骤: 第一步:客户点击登录页,自动跳转到微信服务器端获取code 第二步:用第一步获取的code去获取客户的ac ...

  6. AEAI CRM V1.6.0 升级说明,开源客户关系管理系统

    1 升级说明 AEAI CRM v1.6.0版是AEAI CRM v1.5.2版客户关系管理系统的升级版本,本次版本是基于AEAI DP v3.8.0_20170228进行打包部署的,升级内容主要是针 ...

  7. 基于CRM跟进(活动)记录中关键字识别的客户跟进加权值的成单概率算法

    1.提取销售人员的跟进记录,分析其中的骂人文字(负面情绪),将有负面情绪的客户的跟进排期,进行降权(权重)操作.重点跟进加权值较高的客户. 执行办法: 将销售与客户沟通的语音:电话,微信,QQ,通过调 ...

  8. crm销售管理系统一

    一.环境配置 1.首先配置pip,环境变量配置 pip 9.0.1 from c:\users\administrator\envs\crm\lib\site-packages (python 3.6 ...

  9. python 全栈开发,Day108(客户管理之权限控制,客户管理之动态"一级"菜单,其他应用使用rbac组件,django static文件的引入方式)

    一.客户管理之权限控制 昨天的作业,有很多不完善的地方 下载代码,基本实现权限验证 https://github.com/987334176/luffy_permission/archive/v1.2 ...

随机推荐

  1. plsql常用函数

    1)处理字符的函数 || 或 CONCAT---并置运算符. 格式∶CONCAT(STRING1, STRING2) 例:’ABC’|| ’DE’=’ABCDE’ CONCAT(‘ABC’,’DE’) ...

  2. [IIS] IIS网站对文件读写无权限的解决方案(Access等)

    Access数据库无写权限:在NTFS文件安全属性中加入对IIS_IUSRS用户的修改权限即可.

  3. vs2017 调试时出现 cannot connect to runtime process错误

    用Visual Studio 2017 .net core进行开发时 ,调试运行项目时出现如下错误 解决方案,调试>选项,取消勾选,关闭对JavaScript的调试

  4. 使用python来建立http服务

    python建立http服务 首先我们的windos上要安装python解释器,然后进入我要想要传递的文件的目录下,从当前的目录下进入cmd 然后通过Python解释器输入 python -m htt ...

  5. Linux装python3

     记住下载的软件最好装在/opt下默认的 大家都这样做 linux装python3.7我们以安装最新的来做测试 先下载关联的包防止出错 安装python前的库环境,非常重要yum install gc ...

  6. 封装简单的mvc框架

    MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式. MVC把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller). PH ...

  7. oracle监听,数据库,oracle服务器的启动和停用

    一.oracle监听,数据库,oracle服务器的启动和停用 使用root用户登录:切换用户su – root/root操作系统,一般只有root用户才有权限去操作系统中安装的oracle数据库服务器 ...

  8. Windows Server 2008搭建域控制器

    前言 1.为什么要建域 工作组的分散管理模式不适合大型的网络环境下工作,域模式就是针对大型的网络管理需求设计的,就是共享用户账号,计算机账号和安全策略的计算机集合.域中集中存储用户账号的计算机就是域控 ...

  9. September 07th 2017 Week 36th Thursday

    With the most true of yourself, can you meet the most suitable one. 用最真实的自己,才能遇见最合适的那个人. You are alw ...

  10. ASP.NET Web Api vs Node.js Benchmark

    http://mikaelkoskinen.net/post/asp-net-web-api-vs-node-js-benchmark ASP.NET Web Api vs Node.js Bench ...