crm

2018/01/04 22:23
阅读数 87

crm
功能业务:描述基于RBAC对使用统计人员进行权限控制对学校,老师,班级和销售进行统一管理
其中涉及销售报表和跟进记录并对销售人员成单比进行统计,全体的客户公共的客户,读取
我的客户,我的客户和三天未跟进十五天未成单的要更新,更新不依赖点依赖定时任务以及
对于班级评分作业管理对实现公司会议室的预定。
为什么开发crm给自己公司用,原来人少依赖excal保存,人员部门增加后,目的给销售使用
销售管理
-分配订单
-订单失效(3天,15天)
-销售数据
—数据保存
学校管理
-学校
-课程
-班级
-上课
-作业成绩
—题库
会议室预定
满意度调查
题库
开发周期
- (ps:在公司给你业务开发周期:预计2周,技术点有些不太确定,先进行评估然后在给老大答案。)
- crm开发两周,2个月还在做:修复bug和新功能的开发
开发阶段:
—只开发业务
项目维护和扩展:
-抽离组件以后便于使用其他系统的快速的应用

功能:基于Django和中间件session实现自定义权限组件,粒度到按钮级别
权限系统
---集成rbac app
---共有5个类7个表(menu--group--permissions--user--Role)(用户角色 ,角色权限manytomany 共7张表)
调查问卷(
Userinfo 员工表
员工名字
ClassList 班级表
班级名字
Student 学生表
用户名
密码
Foreignkey(班级表)
Questionnaire 问卷表
问卷名字
ForeignKey(班级表)
ForeignKey(员工表)
Question 问题表
问题
问题类型
(1, 打分
2,单选
3,评价)
ForeignKey(问卷表)
Option 单选题的选项表
选项名称
选项对应的分值
ForeignKey(问题表)
Answer 回答表
ForeignKey(学生表)
ForeignKey(问题表)
ForeignKey(单选题的选项表)
val
content
共:7张表 7个类
---录入权限
-在permissions中录入URL对应的code
---由管理员(admin 123)
-创建其他用户,如:cto,ceo,销售,XXXXX
-用户分配角色
-创建角色
-角色分配权限(ps:不应用rbac,只是在表中插入数据)
---应用权限
--- 中间件
--登录
--权限
---模板和静态文件
-- 优先外部
-- 然后app内
---后台管理布局
---编写权限类
-code
-钩子函数
-基本权限
—非基本权限
基于Bootstrip实现页面展示
基于Bootstrip datetime picker实现会议室预定(userinfo--MeetingRoom--Booking )
会议室预定(model表)
userinfo 用户表
用户名
密码
MeetingRoom 会议室
会议室名称
Booking 会议室预定
ForeignKey(用户)
ForeignKey(会议室)
DateField(预定日期)
基于form实现问卷调查 (userinfo--classList--student--Questionnaire--question--option--answer)
调查问卷表
Userinfo 员工表
员工名字
ClassList 班级表
班级名字
Student 学生表
用户名
密码
Foreignkey(班级表)
Questionnaire 问卷表
问卷名字
ForeignKey(班级表)
ForeignKey(员工表)
Question 问题表
问题
问题类型
(1, 打分
2,单选
3,评价)
ForeignKey(问卷表)
Option 单选题的选项表
选项名称
选项对应的分值
ForeignKey(问题表)
Answer 回答表
ForeignKey(学生表)
ForeignKey(问题表)
ForeignKey(单选题的选项表)
val
content
共:7张表 7个类
基于HighChart对销售进行可视化显示
实现参考Django源码实现自定义stark的组件的开发,并完成定制列,组合查询 ,增删改查等功能
1,stark组件
-单例模式(2种),什么时候用单例模式?
-当希望程序运行起来时,永远只需要一份
-全局变量(全局变量+类)
-单例模式
-使用:stark组件,redis连接(crm自动分配订单).数据库连接+数据库连接池)
-类
FilterRow,可迭代对象
FilterOption,用于封装配置,多选等
ChangeList,封装页面所有功能
StarkConfig,处理用户请求的基类
-配置
-list_display
get_list_display()
_edit_link
-comb_filter
-search_field
-action
-add_btn
-model_from
_视图函数
_uel处理
StarkSite,保存对应关系 {model.UserInfo:StarkConfig(..),
-可迭代对象
-inclusion_tag
-重点:预留钩子,以后用于做权限判断
2, - 基于stark为每一个类生成url
- 反向生成URL
- 根据类获取
- 增删改查
- 到底有几张表?每张表时干什么的?
- 基本curd
- 支持扩展
PS: 遇到过坑,难题?
- pop+limit_choice_to
- 开发组件,
- 参考django中间件:
rbac.middleware.rabc.RbacClass
- rsplit
- importlib
- getattr()
使用:推送消息提醒
问题:函数和方法的区分 粗心大意写了方法传的时候写的时候又传self明明对,
单独写出来发现是混淆了

crm主要的业务功能业务介绍(重点三张表的业务关系,客户表-----客户分配表------销售权重和数量)
客户
公共客户条件:未报名 并且 ( 15天未成单(当前时间-15 > 接客时间) or 3天未跟进(当前时间-3天>最后跟进日期) ) Q对象
在独立的customer.py文件中有一个CustomerConfig类在定义一个public_view的函数,配置好public_view的url
然后同过引入q方法来把公共客户列表拿到(customer_list),在返回前端用模板渲染循环展示出来出来{%for row
in customer_list%}
def public_view(self,request):
import datetime
ctime = datetime.datetime.now().date()
no_deal = ctime - datetime.timedelta(days=15) # 接客
no_follow = ctime - datetime.timedelta(days=3) # 最后跟进日期
#current_user = 1
# models.Customer.objects.filter(Q(recv_date__lt=no_deal)|Q(last_consult_date__lt=no_follow),status=2).exclude(consultant_id=1)
# 作业:两种方法实现
customer_list = models.Customer.objects.filter(Q(recv_date__lt=no_deal)|Q(last_consult_date__lt=no_follow),status=2)
return render(request,'public_view.html',{'customer_list':customer_list})
我的客户:
我的客户分配表:课程顾问ID 客户ID 接单时间 状态
小明 刘伟 2017-11-11 正在跟进
(特别注意的事在排列客户分配表时候status_choices字段内容按照从小往大排序 1正在跟进----已经成单-----3天未跟进-----15天未成单)
解决分配表更新的方案:
方案一:其他人点击跟进的时候,创建自己的更新记录并更新原来的状态 问题:没人接单
方案二:任何人查看公共资源页面时,找到所有: 3/15记录,在分配表中跟新
方案三:定时任务,执行py文件:操作两张表
- 查找客户表,找到公共资源(xxxx) - 查找分配表中数据,并更新状态(3天/15天)
实现方式一:
update.py
#:只要放在服务器上就能运行
import pymysql
conn = pymysql.connet(...)
cursor = conn.cursor()
cursor.execute('select * from customer where 当前时间-15....')
customers = cursor.fetchall()
for row in customers:
update xxxx set status=3/4
30 01 * * * /usr/local/bin/python /usr/bin/update.py #:在夜间定时执行脚本命令实现刷新
服务:
yum install crontabs
/sbin/service crond start //启动服务
/sbin/service crond stop //关闭服务
vim /etc/crontab
30 01 * * * /usr/local/bin/python /usr/bin/update.py
业务详细:全体的客户公共的客户,读取我的客户,我的客户和三天十五天的要更新,更新不依赖点依赖定时任务
所有客户列表,给销售主管------查询客户表
公共资源,所有销售 -------查询客户表(状态未报名,3天没有跟进,15天没有成单)抢单(给新销售)
我的客户,某个销售------客户分配表(当前登录销售)


当前登录用户的所有客户:在CustomerConfig类在定义一个user_view的函数,配置好url,去session中获取用户登录
的id,通过models方法获得当前用户的所有客户列表
current_user_id = 6
#当前用户的所有客户列表
customers = models.CustomerDistribution.objects.filter(user_id=current_user_id).order_by('status')
return render(request,'user_view.html',{'customers':customers})


手动抢单
在公共客户的前端页({%for rowin customer_list%}),添加一条td标签,是一个抢单的链接
<td> <a href="/stark/crm/customer/{{ row.id }}/competition/">抢单</a> </td>在CustomerConfig
类在定义一个 competition_view_view的函数,配置好url(url(r'^(\d+)/competition/$),首先一定
要判断原来的课程顾问不能是自己,状态必须是未报名的 3/15 只有满足这三种条件情况下才能成为自己的
抢单成功后把记录写到分配表里面去
ctime = datetime.datetime.now().date()
no_deal = ctime - datetime.timedelta(days=15) # 接客
no_follow = ctime - datetime.timedelta(days=3) # 最后跟进日期
row_count = models.Customer.objects.filter(Q(recv_date__lt=no_deal) | Q(last_consult_date__lt=no_follow), status=2,id=cid).exclude(consultant_id=current_user_id).update(recv_date=ctime,last_consult_date=ctime,consultant_id=current_user_id)
if not row_count:
return HttpResponse('手速太慢了')
models.CustomerDistribution.objects.create(user_id=current_user_id,customer_id=cid,ctime=ctime)
return HttpResponse('抢单成功')

2,页面录入客户信息(单条录入客户信息,批量录入客户信息)
市场和运营只管把客户信息通过上面两种方式放在公司系统里面,转化的任务交给销售或者课程顾问成为
自己的客户(经过数据校验,获取销售id,写入数据库),按照他们的权重和能接受

的数量进行分配任务单条录入以后权限给市场和运营查看所有客户信息列表
在CustomerConfig类在定义一个 single_views的函数配置好url,假设modelfrom,显示想要的信息
权重(权重表)权重代表了优先分配客户资源,人数代表出现的次数
销售任务
所有的客户都有自己的一个url 在所有的客户页面又增加了排序功能(未报名在前面已经报名的在后面)
公共资源所有的页面通过模板来渲染出来,一般模板放三个块 css,js,bootstrip 目的:为了以后谁继承了这个模板还能自己定制


用到的一些知识点
1. 通过ChangeList封装好多数据
搜索的用法
用于action中显示数据的文本和values属性值
构造表头
列表页面,数据表内容显示每一行的数据
生成器函数,可迭代的对象)
2. 销售中公共资源:Q查询,3天 15天
3. 使用yield实现
- 生成器函数,对数据进行加工处理
- __iter__和yield配合
4. 获取Model类中的字段对应的对象
class Foo(model.Model):
xx = models.CharField()
Foo.get_field('xx')
5. 模糊搜索功能
6. type创建类(创建动态modelform)
7. 自动派单
- 原来在内存中实现,问题:重启和多进程时,都有问题。
- redis
- 状态
- 原来数据(权重表 权重和个数)
- pop数据
8. 使用 list_diplay配置
list_display = [函数名,]
9. reverse反向生成URL(namesbas+加冒号)
10. 母版
11. ready方法定制起始文件
- 文件导入实现单例模式
12. inclusion_tag
13. 中间件的使用(中间件最多有5个方法,用到的地方权限验证,登录验证,csrftoken,session)
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连接池
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. 深浅拷贝
1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象
的内部的子对象。浅拷贝只是拷贝了一系列引用,当我们在拷贝出来的对象对可修改的数据类型进
行修改的时候,并没有改变引用,所以会影响原对象。而对不可修改的对象进行修改的时候,则是
新建了对象,刷新了引用,所以和原对象的引用不同,结果也就和原对象不同。
2. copy.deepcopy 深拷贝 拷贝对象及其子对象。深拷贝就是将里面引用的对
象重新创建了一遍并生成了一个新的一系列引用。但是对于字符串、数字等不
可修改的对象来说,重新创建一份似乎有点浪费内存,所以等到要修改的时候
再新建对象,刷新引用。这样能达到节省内存的目的。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部