业务逻辑:
业务:
共有三种表:
1.客户表(分配时间,以及最后的跟进时间,当前正在沟通的销售)
2.客户分配表
3.权重表
1.客户信息:
(1)客户信息中有公共客户,自己的客户。而公共客户属于新录入的客户和在规定的时间中某个业务人员没有完成的。假如:
规定在3天业务人员和客户没有进行聊或者是在15天没有完成这个订单并且没有报名,那么这个客户就会属于公共资源,那么就是当前时间
减去15天它如果大于你接单的时间或者当前时间减去3天它大于最后的跟进的时间,那么他就属于公共客户资源(通过Q对象把这个条件构造出来)。
那么这客户你就在无权去访问。
(2)我的客户就是在自己这成单或者是在这15天自己跟进的客户,而在这期间在创建一个客户分配表,分配表中包括它的状态,接单时间,以及客户的ID
和课程顾问的ID。生成一条记录。如果新来一个客户,那么设计一个定时任务,这个定时就好每天在规定的时间的让这个脚本跑一次,那么这个数据
它会在每天事实更新,它具体的功能是:执行py文件:操作两张表,查找客户表,找到它的公共资源,查找分配表中的数据,并更新状态(3天/15天)。
而在事实定时有两种方案:一是:可以同过原生的SQL写,也可以同过django也可以写(必须吧定时任务和django放在一起使用,)
当前用户所有的客户具体实现:创建一个url,首先在session中获取当前用户登录的ID,根据当前用户登录的ID去表中获取他自己的数据
(custmers=models.CustomerDistribution.objects.filter(user_id=current_user_id).order_by('status'))把正在跟进的排在前面已成单的放在最后面
(2.5)在新建的选出没有报名的客户,在没有报名的客户后面加上抢单这个功能,获取当前用户的ID,把客户表中的客户修改,把加接单时间秀干成当前时间,
把跟进时间也改成当前时间,把原来的课程顾问改为现在的课程顾问,把这些修改的数据更新到数据库中(更新时注意,原顾问不是自己,状态是没报名
15天没有成单的,才可以跟新)。在分配表中创建一条数据。
2.自动抢单:
(1) 单条录入:先创建一个url,首先get看到一个页面,(用modelform写一个页面),客户表中新增数据:一获取改分配的课程顾问的id,以及当前的时间
,客户分配表新增数据,获取新创建的客户的ID,顾问的ID。
该分配的 课程顾问:就是按照权重以及按照分配表的的排序来分配,用迭代器来实现,数据库必须存在每个人的权重,在数据中在创建一个销售权重表
表中有个数以及权重。先创建一个文件,在这个文件中写一个静态字段(静态字段包括user,iter_users,reset_status ),下来就是跟中权重在数据库中来去
符合的数据(数据就是销售)把数据库中拿到的数据跟新到静态字段中的user中,而在iter_users是生成迭代器的,
CRM项目的总结:
CRM 项目中它有自己的业务逻辑,自己组件组成
组件又有:stark组件,权限组件,还有就是分页组件
权限组件:
1.权限组件有五大类,七张表,有菜单表,权限组表,权限表,用户表,角色表,还有就是角色和权限属于多对多,自动就生成一张表,用户和角色
也是属于多对多自动生成一张表,这样总共就是七张表。
2.它们的字段有如下:
菜单表:就一个字段菜单名称,
权限组表:有两个字段,组名称,最主要的是一个和菜单表一对多的字段(所属菜单)。
权限表中:有五个字段除了标题,还有就是它的含正则的URL,代码,还有就是和权限组表一对多的字段(所属组),以及自关联那个一对多的字段(组内菜单)。
用户表:四个字段,用户名,密码,邮箱,最主要的是,角色表多对多的字段(具有的所有的角色),
角色表:两个字段,角色名,最主要的也是和权限表中多对多的字段(具有的所有权限)。
stark组件:
1.stark组件,十三个类,十六张表,有部门表,员工表,课程表,校区表,班级表,客户表,客户分配表,销售权重表,客户跟进记录表,缴费记录表,
学生表,上课记录表,学生记录表。及学生和班级多对多生成的表,用户表中班主任和班级表多对多生成的表,客户表和课程表多对多生成的表
2.它们的字段有如下:
部门表:两个字段,部门名称,部门编号(code)
员工表:七个字段,员工姓名,用户名,密码,邮箱,微信唯一的ID(openid),以及和部门一对多关联的字段(部门(depart)),还有就是和权限组件中一对一
关联的用户(用户权限(auth))
课程表:一个字段,课程名称
校区表:一个字段,校区名称
班级表:九个字段,班级(期)(semester),学费,开班日期(start_date),结业日期(graduate_date),说明(memo),和校区一对多的字段(校区),和课程一对多的字段(课程名称(course)),
任课老师和用户表多对多的字段(任课老师(teachers)),班主任和用户表一对多的字段(班主任(tutor))。
客户表: 17个字段 ,QQ,学生姓名,性别(gender),学历(education),毕业学校(graduation_school),所学专业(major),工作经验(experience),职业状态(work_status),目前就职公司(company),当前薪资(salary),客户来源(source)
咨询日期,状态(status)最后跟进日期(last_consult_date),接单时间(recv_date),以及和用户一对多生成的字段(课程顾问(consultant)),和课程多对多的字段(咨询课程(course))
客户分配表:五个字段,跟多信息(memo),状态(status),时间(ctime),以及和用户表一对多的字段(客户顾问(user)),和客户一对多的字段(客户(customer)),
销售权重表:三个字段,数量(num),权重(weight),以及和用户一对多的字段(用户表,唯一关联部门字段(user))
客户跟进记录表:四个字段,跟进日期(date),跟进内容(note),以及和客户表一对多的字段(所咨询的客户(customer)),及和用户一对多的字段(跟踪的人(consultant))
缴费记录表:九个字段,交款日期(date),备注(note),报价金额(quote),成交金额(turnover),费用数额(paid_fee),费用类型(pay_type ),以及和客户表一对多的字段(客户(customer)),和班级表一对多的
字段(班级(class_list)),和用户表一对多的字段(负责的老师(consultant))
学生表:十二个字段,用户名(username),密码(password),紧急联系人(emergency_contract),公司(company),所在区域(location),岗位(position),薪资(salary),福利(welfare),入职时间(date),备注(memo),以及和客户表一对一的字段(客户信息(customer))
和班级表多对多的字段(已报的班级(class_list))
上课记录表:十个字段,上课的次数(day_num),上课的日期(date),本节课程标题(course_title),本节课程内容概要(course_memo),本节有作业(has_homework),本节作业标题(homework_title),作业描述(homework_memo),踩分点(exam)
和班级表一对多的字段(班级(class_obj)),和用户表一对多的字段(讲师(teacher))
学生记录表:九个字段,上课记录(record),本节成绩(score),作业评语(homework_note),备注(note),作业文件(homework),学员备注(stu_memo),提作业的日期(date),和上课记录表一对多的字段(第几天的课程(course_record))
和学生表一对多的字段(学员(student))
1. stark组件
类:
- StarkSite, 单例模式,用于保存 model类和 处 理这个类增删改查的 配置类的对象 models.UserInfo -> UserInfoConfig(models.UserInfo,site)
- StarkConfig, 处理增删改查的基类
- ChangeList, 将列表页面功能封装到了此类中
- FilterRow, 可迭代对象,封装了组合搜索中的一行数据。
- FilterOption, 封装组合搜索的配置信息(数据库字段,是否多选,是否choice)
为什吗开发CRM:
a.给自己的公司用,原来人员少通过excel保存,人员和部门增加之后,目的给销售使用,对于销售:
销售管理
- 分配订单
- 订单失效(3天,15天)
- 销售数据
- 数据留存
学校管理
- 学校
- 课程
- 班级
- 上课
- 作业成绩
- 题库
b. 开发周期:
- 开发周期:预计2周,技术点有些不太确定,先进行评估然后再给老大明确答案。
- 开发2个月,2个月持续还在做:修复bug和新功能的开发。
开发阶段:
- 只开发业务
项目维护和扩展:
- 抽离组件以后便于其他系统快速应用。
c.技术点:
有没有遇到坑?令你印象深刻的事情?你觉得写的比较吊的功能。
1.组合搜索时,生成URL:
- request.GET
- 深拷贝
- 可迭代对象
- yield
- 面向对象封装
2.popup
- window.open("",'name')
- opener.xxxxxxx()
- FK时,可以使用 limit_choice_to 可以是字典和Q对象
- related_name和model_name
- 获取所有的反向关联字段,获取limit_choice_to字段
- 查询
3.excel批量导入
4.路由系统
- 动态生成URL
- 看Admin源码(include)
- /xx/ -> ([
'xxx',
],namespace)
- 开发组件时,最开始看到admin源码不太理解,当和权限系统配合时,才领悟其中真谛。
d.其他
1.通过ChangeList封装好多数据
2.销售公共客户资源,用Q对象来查询
3.使用yield实现
- 生成器函数,对数据进行加工处理
- __iter__和yield配合
4. 获取Model类中的字段对应的对象
class Foo(model.Model):
xx = models.CharField()
Foo.get_field('xx')
5. 模糊搜索功能
6. Type创建类
TempForm = type('TempForm',(Form,),{
'score_%s' %obj.pk:fields.ChoiceField(choices=models.StudyRecord.score_choices),
'homework_note_%s' %obj.pk: fields.CharField(widget=widgets.Textarea())
})
7. 自动派单
- 原来在内存中实现,问题:重启和多进程时,都有问题。
- redis
- 状态
- 原来数据(权重表 权重和个数)
- pop数据
方法:# 字符串
conn.get('xx')
conn.set('xx','1')
# 列表
conn.lpush()
conn.rpush()
conn.lpop()
conn.rpop()
conn.llen()
conn.lindex()
# 公共
conn.delete()
8. 使用 list_diplay配置
list_display = [函数名,]
9. reverse反向生成URL
10. 母版
11. ready方法定制起始文件
- 文件导入实现单例模式
12. inclusion_tag
13. 中间件的使用(-用户登录
- 日志记录
- csrf
- session
- 权限管理***)
中间件参数:process_request
process_view
process_template_response
process_reponse
process_exception
15. importlib + getattr
16. FilterOption,lambda表达式
17. QueryDict
- 原条件的保留
- filter
18. ModelForm
19. 面向对象的 @property(不用加括号) @classmethod
20. mark_safe(将二进制转换为字符串)
21. 抽象方法抽象类+raise Im...
22. 组件中的装饰器,实现self.request = request
23. 自执行函数
(function(arg){
})('sf')
24. URL的钩子函数
25. 多继承
26. 批量导入,xlrd
27. redis连接池 端口是:6379
28. 工厂模式
settings.py
MSG_PATH = "path.Email"
class XXFactory(object):
@classmethod
def get_obj(cls):
settings.MSG_PATH
# rsplit
# importlib
# getattr
return obj
class Email(object):
def send ...
class WeChat(object):
def send ...
class Msg(object):
def send ...
29. Models类中自定义save方法
30. django admin中注册models时候
from django.contrib import admin
from . import models
# 方式一
class UserConfig(admin.ModelAdmin):
pass
admin.site.register(models.UserInfo,UserConfig)
# 方式二
@admin.register(models.UserInfo)
class UserConfig(admin.ModelAdmin):
pass
31. 深浅拷贝
浅拷贝:不管多么复杂的数据结构,浅拷贝都只会copy一层。
深拷贝:其实深拷贝就是在内存中重新开辟一块空间,不管数据结构多么复杂,只要遇到可能发生改变的数据类型,
就重新开辟一块内存空间把内容复制下来,直到最后一层,不再有复杂的数据类型,就保持其原引用。这样,
不管数据结构多么的复杂,数据之间的修改都不会相互影响。这就是深拷贝
深拷贝用过:分页
32.事物:with transaction.atomic():
33.数据实时跟新用:__init__
34.用于Action中显示数据的文本和value属性值
用什么拿函数名:用__name__
函数取值:用func.short_desc=""
35.对象,判断是否是某个类型?
用type(精确)或isinstancec(不精确)
36.在前端中模板语言中不能用下划线开头,也不能用双下划线开头
37. FK 中,limit_choice_to可以是字典,也可以是Q对象
38.单列模式:
- 单例模式(2中),什么时候用单例模式?
- 当希望程序运行起来时,永远只需要一份。
- 全局变量(全局变量+类)
- 单例模式
- 使用:stark组件、redis连接(crm自动分配订单)、数据库连接+数据库连接池