当前位置:   article > 正文

Django项目:CRM(客户关系管理系统)--85--75PerfectCRM实现CRM扩展权限

Django项目:CRM(客户关系管理系统)--85--75PerfectCRM实现CRM扩展权限

 

 

 1 # sales_urls.py
 2 # ————————47PerfectCRM实现CRM客户报名流程————————
 3 from django.conf.urls import url
 4 from bpm.sales import sales_views
 5 
 6 urlpatterns = [
 7 
 8     # ————————75PerfectCRM实现CRM扩展权限————————
 9     url( r'^sales_customer/$', sales_views.sales_customer, name='sales_customer' ),  # 销售自己的客户库
10     # ————————75PerfectCRM实现CRM扩展权限————————
11 
12     url(r'^customer/(\d+)/enrollment/$', sales_views.enrollment, name="enrollment"),#客户招生#报名流程一 下一步
13 
14     # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
15     # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
16     # url(r'^customer/registration/(\d+)/$', sales_views.stu_registration, name="stu_registration"),  # 报名流程二 学员签同合
17     # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
18     url(r'^customer/registration/(\d+)/(\w+)/$', sales_views.stu_registration, name="stu_registration"),  # 报名流程二 学员签同合
19     # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
20 
21     # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
22     url(r'^contract_prompt/$', sales_views.contract_prompt, name="contract_prompt"),  # 报名流程二 提示学员
23     url(r'^not_audit/$', sales_views.not_audit, name="not_audit"),  # 报名流程二  未审核 查询
24     url(r'^contract_review/(\d+)/$', sales_views.contract_review, name="contract_review"),  # 报名流程三  审核
25     url(r'^enrollment_rejection/(\d+)/$', sales_views.enrollment_rejection, name="enrollment_rejection"),  # 报名流程三 驳回
26     # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
27 
28 ]
29 # ————————47PerfectCRM实现CRM客户报名流程————————
# sales_urls.py

 

 

 

  1 # sales_views.py
  2 # ————————47PerfectCRM实现CRM客户报名流程————————
  3 from django.db import IntegrityError  # 主动捕捉错误信息
  4 from django.shortcuts import render  # 页面返回
  5 from crm import models  # 数据库
  6 from bpm.bpm_auxiliary import bpm_forms  # 自定制 forms
  7 from  django.contrib.auth.decorators import login_required  # 登陆后页面才能访问
  8 
  9 # ————————47PerfectCRM实现CRM客户报名流程————————
 10 from django.core.mail import send_mail
 11 # send_mail的参数分别是  邮件标题,邮件内容,发件箱(settings.py中设置过的那个),收件箱列表(可以发送给多个人),失败静默(若发送失败,报错提示我们)
 12 import random
 13 import datetime  # 获取时间#登陆过期
 14 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL————————
 15 from permissions.permission import check_permission #权限控制
 16 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL————————
 17 
 18 
 19 # ————————75PerfectCRM实现CRM扩展权限————————
 20 #销售自己的客户库
 21 def sales_customer(request):
 22     user_id=request.user.id #当前登陆的ID
 23     return redirect( '/king_admin/crm/customer/?consultant=%s' %(user_id) )  # 跳转到enrollment_rejection
 24 # ————————75PerfectCRM实现CRM扩展权限————————
 25 
 26 
 27 # 发送邮件的功能 #验证码#密码
 28 class stmp():
 29     def __init__(self):
 30         self.emaillist = []  # 发送给谁
 31         self.code = None  # 验证码#密码
 32 
 33     def stmps(self, request, email, msg_mail):  # 传参数#页面,session #邮箱,发送给谁 #内容
 34         self.emaillist.append(email)  # 将邮箱地址添加到调用Django发送邮件功能
 35         # ——————生成验证码——————
 36         _letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小写字母,去除可能干扰的i,l,o,z
 37         _upper_cases = _letter_cases.upper()  # 大写字母
 38         _numbers = ''.join(map(str, range(3, 10)))  # 数字
 39         chars = ''.join((_letter_cases, _upper_cases, _numbers))  # 变成一条字符串
 40         list = random.sample(chars, 4)  # 从一条字符串随机选4个字符变成列表
 41         self.code = ''.join(list)  # 列表变字符串
 42         # ——————生成验证码——————
 43         # ——————调用Django发送邮件——————
 44         title = 'PerfectCRM项目自动邮件:%s' % self.code  # 邮件标题#防止一样的内容被邮箱屏蔽
 45         send_mail(title,  # 邮件标题
 46                   msg_mail,  # 验证码内容
 47                   'perfectcrm@sina.cn',  # 发送的邮箱  #根据情况重新配置
 48                   self.emaillist,  # 接受的邮箱
 49                   fail_silently=False,  # 静默,抛出异常
 50                   )
 51         print('发送邮件成功!没收到要换标题!检查发送邮箱的配置!')
 52         # ——————调用Django发送邮件——————
 53 # ————————47PerfectCRM实现CRM客户报名流程————————
 54 # ————————47PerfectCRM实现CRM客户报名流程————————
 55 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
 56 import random  # 随机
 57 import string  # 字母 数字
 58 from django.core.cache import cache  # 缓存
 59 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
 60 
 61 # 报名填写 销售
 62 @login_required  # 登陆后页面才能访问
 63 @check_permission #权限控制
 64 def enrollment(request, customer_id):
 65     msgs = {}  # 错误信息
 66     customer_obj = models.Customer.objects.get(id=customer_id)  # 取到客户信息记录 #返回到页面#报名人
 67     consultant_obj = models.UserProfile.objects.get(id=request.user.id)  # 报名课程顾问
 68 
 69     stmp_mail = {}  # 邮件发送成功
 70     stmpemail = stmp()  # 实例化发送邮件的功能
 71     email = request.POST.get('email')  # 让页面POST提交的值,在页面GET后仍然存在显示
 72     if request.method == "POST":
 73         enroll_form = bpm_forms.EnrollmentForm(request.POST)  # 获取数据
 74         if enroll_form.is_valid():  # 表单验证
 75 
 76             # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
 77             # msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/"
 78             msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/{random_str}/ "
 79             random_str = ''.join(random.sample(string.ascii_lowercase + string.digits, 8))  # 生成8位随机字符串 #URL使用
 80             url_str = '''customer/registration/{enroll_obj_id}/{random_str}/'''  # 报名链接
 81             # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
 82 
 83             try:
 84                 enroll_form.cleaned_data['customer'] = customer_obj  # 添加学员对象 记录 #报名人
 85                 enroll_form.cleaned_data['consultant'] = consultant_obj  # 报名课程顾问
 86                 enroll_obj = models.Enrollment.objects.create(**enroll_form.cleaned_data)  # 创建记录
 87 
 88                 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
 89                 # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#报名记录对应的id,随机字符串,报名链接
 90                 sort_url = enroll_obj.id  # 获取报名表对应的ID
 91                 cache.set(enroll_obj.id, random_str, 61000)  # 加入过期时间   #URL使用    # cache缓存
 92                 msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str)  # 报名记录对应的id,随机字符串,报名链接
 93                 url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str)  # 报名链接
 94                 print(url_str)
 95                 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
 96             except IntegrityError as e:
 97                 # 取到这条记录
 98                 enroll_obj = models.Enrollment.objects.get(customer_id=customer_obj.id,
 99                                                            enrolled_class_id=enroll_form.cleaned_data[
100                                                                'enrolled_class'].id)
101 
102                 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
103                 if enroll_obj.contract_agreed:#学员已经同意合同,提交了身份证
104                     #return redirect('/crm/contract_review/%s/'%enroll_obj.id)#跳转到审核页面
105                     return render(request,'bpm_sales/contract_prompt.html',locals())#跳转提示页面
106                 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
107 
108                 enroll_form.add_error('__all__', '记录已经存在,不能重复创建!')
109 
110                 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
111                 # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#报名记录对应的id
112                 cache.set(enroll_obj.id, random_str, 61000)  # 加入过期时间  #URL使用    # cache缓存
113                 msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str)  # 报名记录对应的id
114                 url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str)  # 报名链接
115                 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
116 
117             if email:
118                 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
119                 # msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s" %enroll_obj.id
120                 msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s/%s" %(enroll_obj.id,random_str)
121                 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
122                 stmpemail.stmps(request, email, msg_mail)  # 发送邮件
123                 stmp_mail['ok'] = "邮件已发送成功!"
124 
125     else:
126         enroll_form = bpm_forms.EnrollmentForm()  # modelform表单
127     return render(request, 'bpm_sales/enrollment.html', locals())
128 # ————————47PerfectCRM实现CRM客户报名流程————————
129 
130 
131 # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
132 #学员合同签定
133 
134 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
135 import os
136 from PerfectCRM import settings
137 import json
138 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
139 
140 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
141 from django.shortcuts import HttpResponse #页面返回
142 # def stu_registration(request,enroll_id):
143 def stu_registration(request,enroll_id,random_str):
144     # enroll_obj=models.Enrollment.objects.get(id=enroll_id)#获取报名记录
145     if cache.get(enroll_id) == random_str:  # 判断链接失效了没有
146         enroll_obj = models.Enrollment.objects.get(id=enroll_id)  # 报名记录
147 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
148 
149         # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
150         enrolled_path='%s/%s/'%(settings.ENROLLED_DATA,enroll_id)#证件上传路径
151         img_file_len=0  #文件
152         if os.path.exists(enrolled_path):#判断目录是否存在
153             img_file_list=os.listdir(enrolled_path)#取目录 下的文件
154             img_file_len=len(img_file_list)
155         # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
156 
157     # ————————49PerfectCRM实现CRM客户报名流程学生合同表单验证————————
158         # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
159         if request.method == "POST":
160 
161             # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
162             ret=False
163             data=request.POST.get('data')
164             if data:#如果有删除动作
165                 del_img_path="%s/%s/%s"%(settings.ENROLLED_DATA,enroll_id,data)#路径
166                 print(del_img_path,'=-=-=-=-=-=')
167                 os.remove(del_img_path)
168                 ret=True
169                 return HttpResponse(json.dumps(ret))
170             if request.is_ajax():#ajax上传图片 #异步提交
171                 print('ajax上传图片 #异步提交中。。。 ',request.FILES)
172                 enroll_data_dir="%s/%s"%(settings.ENROLLED_DATA,enroll_id)#路径  #重要信息不能放在静态文件中
173                 if not os.path.exists(enroll_data_dir):#如果不存目录
174                     os.makedirs(enroll_data_dir,exist_ok=True)#创建目录
175                 for k,file_obj in request.FILES.items():   #循环字典 #上传的文件
176                     with open("%s/%s"%(enroll_data_dir,file_obj.name),'wb') as f: #打开一个文件#路径#获取文件名
177                         for chunk in file_obj.chunks():#循环写入文件 # chunks块
178                             f.write(chunk)  #保存文件
179                 return HttpResponse('上传完成!')
180             # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
181 
182             customer_form = bpm_forms.CustomerForm(request.POST, instance=enroll_obj.customer)  # 生成表单验证
183             if customer_form.is_valid():  # 表单验证通过
184                 customer_form.save()  # 保存
185                 enroll_obj.contract_agreed = True  # 同意协议
186                 enroll_obj.save()  # 保存
187                 status = 1  # 修改报名状态 # 1 已经报名
188                 return render(request, 'bpm_sales/stu_registration.html', locals())
189 
190         else:
191             if enroll_obj.contract_agreed == True:  # 如果协议已经签订
192                 status = 1  # 修改报名状态 # 1 已经报名
193             else:
194                 status = 0
195             customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer)  # 生成表单
196     # customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer)  # 生成表单
197     # ————————49PerfectCRM实现CRM客户报名流程学生合同表单验证————————
198 
199         return render(request,'bpm_sales/stu_registration.html',locals())
200         # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
201 # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
202     # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
203     else:
204         return HttpResponse('链接失效,非法链接,请自重!')
205     # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
206 
207 
208 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
209 from django.shortcuts import redirect
210 #查询流程提示页面
211 def contract_prompt(request,enroll_id):
212     enroll_obj=models.Enrollment.objects.get(id=enroll_id)#取对象
213     enroll_form= bpm_forms.EnrollmentForm(instance=enroll_obj)#报名表对象
214     customers_form= bpm_forms.CustomerForm(instance=enroll_obj.customer)#学员的信息
215     return render(request,'bpm_sales/contract_prompt.html',locals())
216 
217 # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
218 from bpm.bpm_auxiliary.pagination import Page #分页
219 # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
220 # #待审核
221 @login_required # 登陆后页面才能访问
222 @check_permission #权限控制
223 def not_audit(request):
224     # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
225     # sign=models.Enrollment.objects.all()#所有的报名表
226     # print(sign,'sign----->')
227     sign=models.Enrollment.objects.filter(contract_agreed=True,contract_approved=False).all()#所有的报名表
228 
229     page = Page(request.GET.get('p', 1), len(sign)) #当前页数 默认为1 #总数量
230     sign = sign[page.start:page.end]  # 切片取当前页的数据
231     page_str = page.page_str('/bpm/not_audit/')  #总页数 传入url
232     # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
233     return render(request, 'bpm_sales/not_audit.html', locals())#
234 
235 #审核合同
236 @login_required # 登陆后页面才能访问
237 @check_permission #权限控制
238 def contract_review(request,enroll_id):
239     enroll_obj=models.Enrollment.objects.get(id=enroll_id)#取对象
240     contract_review = request.user.name #当前登陆人 #合同审核人
241     #payment_form=forms.PaymentForm()#生成表单
242     enroll_form= bpm_forms.EnrollmentForm(instance=enroll_obj)#报名表对象
243     customer_form= bpm_forms.CustomerForm(instance=enroll_obj.customer)#学员的信息
244     enrolled_path='%s/%s/'%(settings.ENROLLED_DATA,enroll_id)#证件上传路径
245     if os.path.exists(enrolled_path):#判断目录是否存在
246         file_list=os.listdir(enrolled_path)#取目录 下的文件
247         imgs_one=file_list[0]  #图片1
248         imgs_two=file_list[1]  #图片2
249     if request.method=="POST":
250         enroll_obj.contract_approved = True  # 审核通过
251         enroll_obj.save() #保存
252         enroll = models.Enrollment.objects.filter(id=enroll_id).update(contract_review=contract_review)#合同审核人
253         print('审核通过。。。')
254         return redirect('/bpm/not_audit/')#跳转到待审核
255     return render(request, 'bpm_sales/contract_review.html', locals())#
256 #驳回合同
257 def enrollment_rejection(request,enroll_id):
258     enroll_obj=models.Enrollment.objects.get(id=enroll_id)#报名表的对象
259     enroll_obj.contract_agreed=False#修改学员已经同意核同
260     enroll_obj.save() #保存
261     return redirect('/bpm/customer/%s/enrollment/'%enroll_obj.customer.id)#跳转到enrollment_rejection
262 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
# sales_views.py

 

 

 

  1 #models.py
  2 
  3 # ————————01PerfectCRM基本配置ADMIN————————
  4 
  5 from django.db import models
  6 # Create your models here.
  7 
  8 """
  9 #运行 Terminal
 10 #    生成 数据表
 11 #    python manage.py makemigrations
 12 #   数据表 迁移
 13 #    python manage.py migrate
 14 """
 15 
 16 """01校区表"""
 17 class Branch(models.Model):
 18     name = models.CharField(max_length=128,unique=True) #校区名#CharField作用是保存文本,定长的变量类型
 19     addr = models.CharField(max_length=128) #地址
 20     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
 21         return self.name #返回 #校区名
 22     class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据
 23         verbose_name_plural =  "01校区表" #verbose_name_plural给你的模型类起一个更可读的名字
 24 
 25 """02班级表"""
 26 class ClassList(models.Model):
 27     #ForeignKey就是表与表之间的某种约定的关系  #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
 28     branch = models.ForeignKey("Branch",on_delete=models.CASCADE)#校区    关联到  校区表
 29     course = models.ForeignKey("Course",on_delete=models.CASCADE) #课程   关联到   课程表
 30 
 31     # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
 32     contract = models.ForeignKey('ContractTemplate', blank=True, null=True, default=1,on_delete=models.CASCADE)  # 合同表
 33     # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
 34 
 35     class_type_choices = ( #上课形式
 36                           (0,'面授(脱产)'),
 37                           (1,'面授(周末)'),
 38                           (2,'网络班'),)
 39     #PositiveSmallIntegerField正小整数 0 ~ 32767 #choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
 40     class_type = models.SmallIntegerField(choices=class_type_choices)#上课形式
 41 
 42     #PositiveSmallIntegerField正小整数 0 ~ 32767
 43     semester = models.PositiveSmallIntegerField(verbose_name="学期") #课程的第几期
 44 
 45     #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。
 46     teachers = models.ManyToManyField("UserProfile") # 老师   关联到    账号表
 47 
 48     start_date = models.DateField(verbose_name="开班日期") #DateField 日期格式 YYYY-MM-DD #verbose_name是Admin中显示的字段名称
 49 
 50     # DateField 日期格式 YYYY-MM-DD #verbose_name是Admin中显示的字段名称 #Django可空#数据库可以为空
 51     end_date = models.DateField(verbose_name="结业日期",blank=True,null=True)
 52 
 53     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
 54         return "%s %s %s" %(self.branch,self.course,self.semester) #返回 #%s格式化输出字符串 #校区#课程# 学期
 55     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
 56         unique_together=('branch','course','semester')  #联合索引
 57         verbose_name_plural = "02班级表" #verbose_name_plural给你的模型类起一个更可读的名字
 58 
 59 """03课程表,可以报名那些课程"""
 60 class Course(models.Model):
 61     name = models.CharField(max_length=64,unique=True)#课程名 #CharField作用是保存文本,定长的变量类型
 62     price = models.PositiveSmallIntegerField(verbose_name="学费")#学费#PositiveSmallIntegerField正小整数 0 ~ 32767
 63     period = models.PositiveSmallIntegerField(verbose_name="周期(月)") #PositiveSmallIntegerField正小整数 0 ~ 32767
 64     outline = models.TextField() #课程大纲  #文本类型
 65     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
 66         return self.name #返回 #课程名
 67     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
 68         verbose_name_plural =  "03课程表"#verbose_name_plural给你的模型类起一个更可读的名字
 69 
 70 '''04客户信息表'''
 71 class Customer(models.Model):
 72     name = models.CharField(max_length=32,blank=True,null=True)#客户名#CharField定长文本 #名字最长32 # Django可空 #数据库可以为空
 73     qq = models.CharField(max_length=64,unique=True) #QQ号#CharField定长文本 #名字最长64 #唯一,不能重复
 74     qq_name = models.CharField(max_length=64,blank=True,null=True)#QQ名 #CharField定长文本 #名字最长64 # Django可空 #数据库可以为空
 75     phone = models.CharField(max_length=64,blank=True,null=True)#手机号 #CharField定长文本 #名字最长64 # Django可空 #数据库可以为空
 76 
 77     # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
 78     id_num=models.CharField(max_length=64,blank=True,null=True,verbose_name='身份证号')#身份证号
 79     email=models.EmailField(max_length=64,blank=True,null=True,verbose_name='邮箱')#email
 80     sex_choices=((0,'保密'),(1,''),(2,''))
 81     sex=models.SmallIntegerField(choices=sex_choices,default=0,verbose_name='性别')
 82     # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
 83 
 84     # ————————53PerfectCRM实现CRM客户报名流程缴费————————
 85     status_choices = ((0, '已报名'), (1, '未报名'), (2, '已退学'))
 86     status = models.SmallIntegerField(choices=status_choices, default=1)  # 学员状态
 87     # ————————53PerfectCRM实现CRM客户报名流程缴费————————
 88 
 89     source_choices = ( #客户渠道来源 (内存生成)
 90                       (0,'转介绍'),
 91                       (1,'QQ群'),
 92                       (2,'官网'),
 93                       (3,'百度推广'),
 94                       (4,'51CTO'),
 95                       (5,'知乎'),
 96                       (6,'市场推广'),)
 97     #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
 98     source = models.SmallIntegerField(choices=source_choices)#客户渠道来源
 99 
100     #CharField定长文本#verbose_name是Admin中显示的字段名称#名字最长64 # Django可空 #数据库可以为空
101     referral_from = models.CharField(verbose_name="转介绍人qq",max_length=64,blank=True,null=True) #来自谁介绍的
102 
103     #ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
104     consult_courses = models.ForeignKey("Course",verbose_name="咨询课程", on_delete=models.CASCADE) #关联到 课程表
105 
106     content= models.TextField(verbose_name="咨询详情") #TextField无限制长度的文本#verbose_name是Admin中显示的字段名称
107 
108     #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。
109     tags = models.ManyToManyField("Tag",blank=True)#多对多关联到 标签表
110 
111     #ForeignKey就是表与表之间的某种约定的关系  #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
112     consultant = models.ForeignKey("UserProfile", on_delete=models.CASCADE) #关联到  账号表
113 
114     memo = models.TextField(blank=True,null=True)#备注#TextField无限制长度的文本#Django可空#数据库可以为空
115 
116     #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
117     date =  models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
118 
119     def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
120         return self.qq  #返回 #QQ号
121 
122     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
123         verbose_name_plural =  "04客户表" #verbose_name_plural给你的模型类起一个更可读的名字
124 
125 # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
126 #合同模版
127 class ContractTemplate(models.Model):
128     name=models.CharField('合同名称',max_length=64,unique=True)
129     template=models.TextField()
130 
131     def __str__(self):
132         return self.name
133     class Meta:
134         verbose_name_plural='合同表'
135 # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
136 
137 
138 """05客户跟进表"""
139 class CustomerFollowUp(models.Model):
140 
141     #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
142     customer = models.ForeignKey("Customer", on_delete=models.CASCADE)#客户名 #关联到  客户信息表
143 
144     content = models.TextField(verbose_name="跟进内容")#跟进的内容#TextField无限制长度的文本#verbose_name是Admin中显示的字段名称
145 
146     #ForeignKey就是表与表之间的某种约定的关系  #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
147     consultant =models.ForeignKey("UserProfile", on_delete=models.CASCADE) #关联到  账号表
148 
149     intention_choices =(  #报名状态
150                         (0,'2周内报名'),
151                         (1,'1个月内报名'),
152                         (2,'近期无报名计划'),
153                         (3,'已在其它机构报名'),
154                         (4,'已报名'),
155                         (5,'已拉黑'),)
156     #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
157     intention=models.SmallIntegerField(choices=intention_choices) #报名状态
158 
159     #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
160     date =  models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
161 
162     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
163         return "<%s:%s>" %(self.customer.qq,self.intention) #返回#格式化字符串#跨表里的QQ号#报名状态
164     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
165         verbose_name_plural =  "05客户跟进表"#verbose_name_plural给你的模型类起一个更可读的名字
166 
167 """06学员报名信息表"""
168 class Enrollment(models.Model):
169     # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
170     customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字 #关联到  客户信息表
171     enrolled_class = models.ForeignKey("ClassList",verbose_name="所报班级",on_delete=models.CASCADE)#关联到  班级表
172     consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问",on_delete=models.CASCADE) #关联到  账号表
173 
174     # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
175     contract_review = models.CharField(max_length=256, blank=True, null=True, verbose_name="合同审核")  # 合同审核
176     # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
177 
178     #BooleanField布尔值类型#default=False默认(True)不允许出现空字符#verbose_name是Admin中显示的字段名称
179     contract_agreed = models.BooleanField(default=False,verbose_name="学员已经同意合同")#学员看合同
180     contract_approved = models.BooleanField(default=False,verbose_name="合同已经审核") #谁审核
181 
182     # ————————53PerfectCRM实现CRM客户报名流程缴费————————
183     Pay_cost= models.BooleanField(default=False,verbose_name="缴费") #缴费状态#是不是交定金
184     # ————————53PerfectCRM实现CRM客户报名流程缴费————————
185 
186     # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
187     date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
188 
189     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
190         # ————————57PerfectCRM实现admin批量生成上课记录————————
191         # return "%s %s" %(self.customer,self.enrolled_class)#返回#格式化字符串#学员名字#所报班级
192         return " 学员:%s |QQ: %s |班级:%s" %(self.customer.name,self.customer,self.enrolled_class)#返回#格式化字符串#学员名字#所报班级
193         # ————————57PerfectCRM实现admin批量生成上课记录————————
194     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
195         unique_together =  ("customer","enrolled_class")#联合索引
196         verbose_name_plural =  "06学员报名信息表"#verbose_name_plural给你的模型类起一个更可读的名字
197 
198 """07缴费记录表"""
199 class Payment(models.Model):
200     #ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
201     customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字        关联到  客户信息表
202     course = models.ForeignKey("Course",verbose_name="所报课程",on_delete=models.CASCADE)#关联到  课程表
203 
204     #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称#默认值=500
205     amount = models.PositiveIntegerField(verbose_name="数额",default=500)#缴费数额
206 
207     #ForeignKey就是表与表之间的某种约定的关系#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
208     consultant = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#缴费给谁 关联到  账号表 #财务人员
209 
210     #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
211     date=models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
212 
213     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
214         return "%s %s" %(self.customer,self.amount)#返回#格式化字符串#学员名字#缴费数额
215     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
216         verbose_name_plural = "07缴费记录表"#verbose_name_plural给你的模型类起一个更可读的名字
217 
218 """08每节课上课纪录表"""
219 class CourseRecord(models.Model):
220     # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
221     from_class = models.ForeignKey("ClassList",verbose_name="班级",on_delete=models.CASCADE) #那个班级
222 
223     #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称
224     day_num = models.PositiveSmallIntegerField(verbose_name="第几节(天)") #第几节课
225 
226     # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
227     teacher = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#老师是谁    关联到    账号表
228 
229     #BooleanField布尔值类型#default=True默认(True)不允许出现空字符
230     has_homework = models.BooleanField(default=True) #有没有作业
231 
232     # CharField定长文本#名字最长128#Django可空#数据库可以为空
233     homework_title = models.CharField(max_length=128,blank=True,null=True) #作业标题
234 
235     #TextField无限制长度的文本#Django可空#数据库可以为空
236     homework_content = models.TextField(blank=True,null=True) #作业内容
237 
238     #TextField无限制长度的文本#verbose_name是Admin中显示的字段名称
239     outline =models.TextField(verbose_name="本节课程大纲") #课程主要讲什么
240 
241     # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
242     date = models.DateField(auto_now_add=True)#创建时间(数据库自增)
243 
244     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
245         return " %s:%s" %(self.from_class,self.day_num)#返回#格式化字符串#班级#第几节(天)
246     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
247         unique_together = ("from_class","day_num") #联合索引
248         verbose_name_plural = "08每节课上课纪录表" #verbose_name_plural给你的模型类起一个更可读的名字
249 
250 """09学习纪录"""
251 class StudyRecord(models.Model):
252     # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
253     student = models.ForeignKey("Enrollment",on_delete=models.CASCADE)#学生名字   关联到    学员报名信息表
254     course_record = models.ForeignKey("CourseRecord",on_delete=models.CASCADE)#开课记录   # 关联到    每节课上课纪录表
255 
256     attendance_choices = (# 本节课上课状态记录
257                             (0,"已签到"),
258                             (1,"迟到"),
259                             (2,"缺勤"),
260                             (3,"早退"),)
261     #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
262     attendance = models.SmallIntegerField(choices=attendance_choices) # 本节课上课状态记录
263 
264     # ————————63PerfectCRM实现CRM讲师下载作业————————
265     delivery = models.BooleanField(default=False,verbose_name="交作业") #有没有交付作业
266     # ————————63PerfectCRM实现CRM讲师下载作业————————
267 
268 
269     # ————————61PerfectCRM实现CRM学生上传作业————————
270     homework_link = models.TextField(blank=True,null=True)#作业链接 #TextField无限制长度的文本#Django可空#数据库可以为空
271     # ————————61PerfectCRM实现CRM学生上传作业————————
272 
273     score_choices = (#学习成绩
274                      (100,"A+"),
275                      (90,"A"),
276                      (85,"B+"),
277                      (80,"B"),
278                      (75,"B-"),
279                      (70,"C+"),
280                      (65,"C"),
281                      (40,"C-"),
282                      (-20,"D"),
283                      (-50,"COPY"),
284                      (0,"N/A"),)
285     #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
286     score = models.SmallIntegerField(choices=score_choices) #学习成绩
287 
288 
289     memo = models.TextField(blank=True,null=True)#TextField无限制长度的文本#Django可空#数据库可以为空
290 
291     # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
292     date = models.DateField(auto_now_add=True)#创建时间(数据库自增)
293 
294     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
295         return "%s %s %s" % (self.student, self.course_record, self.score)#返回#格式化字符串#学生名字#开课记录#学习成绩
296     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
297         unique_together = ('student','course_record')#联合索引#学生名字#开课记录
298         verbose_name_plural =  "09学习纪录"#verbose_name_plural给你的模型类起一个更可读的名字
299 
300 # ————————34PerfectCRM实现CRM自定义用户————————
301 # """10账号表"""
302 # class UserProfile(models.Model):
303 #     from django.contrib.auth.models import User  # 使用django内置的用户表
304 #
305 #     #OneToOneField一对一  #User是django Admin里的账号表#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
306 #     user = models.OneToOneField(User,on_delete=models.CASCADE)# 用户名 #创建外键,关联django用户表
307 #
308 #     name = models.CharField(max_length=32) #账号名(扩展用户字段)#CharField定长文本
309 #
310 #     #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。#Django可空
311 #     roles = models.ManyToManyField("Role",blank=True) #角色(权限)   # 双向一对多==多对多
312 #
313 #     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
314 #         return self.name #返回 #账号名
315 #     class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据
316 #         verbose_name_plural = "10账号表"#verbose_name_plural给你的模型类起一个更可读的名字
317 # ————————34PerfectCRM实现CRM自定义用户————————
318 
319 # ————————34PerfectCRM实现CRM自定义用户————————
320 #10账号表,创建用户和超级用户
321 from django.contrib.auth.models import BaseUserManager
322 class UserProfileManager(BaseUserManager):
323     def create_user(self, email, name, password=None):
324         """
325       创建并保存一个用户用给定的邮件,日期
326       出生和密码。
327         """
328         if not email:#没有email 报错
329             raise ValueError('用户必须有一个电子邮件地址')
330 
331         user = self.model(
332             email=self.normalize_email(email),#验证邮箱格式
333             name=name,
334         )
335         user.set_password(password)#加密
336         user.is_active = True
337         user.save(using=self._db)
338         return user
339     def create_superuser(self, email, name, password):
340         """
341       创建并保存一个超级用户具有给定邮件,日期
342       出生和密码。
343         """
344         user = self.create_user(email,
345             password=password,
346             name=name
347         )
348         user.is_active = True
349         user.is_superuser = True
350         user.save(using=self._db)
351         return user
352 
353 """10账号表"""
354 """
355 
356 #删除数据库
357 
358 #调用objects = UserProfileManager()#创建账号 #关联这个函数
359 
360 #运行 Terminal
361 #    生成 数据表
362 #    python manage.py makemigrations
363 #   数据表 迁移
364 #    python manage.py migrate
365 Django Admin里账号密码重置方法
366 #运行 Terminal  
367 python manage.py createsuperuser
368 
369 Email address:          admin@qq.com
370 用户名 :                 admin
371 Password:               admin123456
372 Password (again):       admin123456
373 """
374 from django.contrib.auth.models import AbstractBaseUser
375 # ————————35PerfectCRM实现CRM重写Admin密码修改————————
376 from django.utils.translation import ugettext_lazy as _  # 语言国际化
377 from django.utils.safestring import mark_safe
378 from django.contrib.auth.models import PermissionsMixin
379 # class UserProfile(AbstractBaseUser):
380 class UserProfile(AbstractBaseUser,PermissionsMixin):
381 # ————————35PerfectCRM实现CRM重写Admin密码修改————————
382     email=models.EmailField(
383         verbose_name='邮箱账号',
384         max_length=255,
385         unique=True#唯一  #登陆账号
386     )
387     name=models.CharField(max_length=32,verbose_name='用户名')
388 
389 
390     # ————————72PerfectCRM实现CRM动态菜单和角色————————
391     branch = models.ForeignKey( "Branch", verbose_name="所属校区", blank=True, null=True, on_delete=models.CASCADE )
392     roles = models.ManyToManyField( 'Role', verbose_name="角色", blank=True )
393     memo = models.TextField( blank=True, null=True, default=None, verbose_name="备注" )
394     from django.utils import timezone
395     date_joined = models.DateTimeField( verbose_name="创建时间", default=timezone.now )
396     # ————————72PerfectCRM实现CRM动态菜单和角色————————
397 
398     # ————————35PerfectCRM实现CRM重写Admin密码修改————————
399     password = models.CharField(_('password'), max_length=128, help_text=mark_safe('''<a href=\"../password/\">修改密码</a>'''))
400     # ————————35PerfectCRM实现CRM重写Admin密码修改————————
401 
402     is_active = models.BooleanField(default=True,verbose_name='合法账号')#权限#合法账号
403     is_superuser = models.BooleanField(default=False,verbose_name='超级账号') #超级账号
404     objects = UserProfileManager()#创建账号 #关联这个函数
405     USERNAME_FIELD ='email'#指定做为  #登陆账号
406     REQUIRED_FIELDS = ['name']#必填字段
407 
408 
409     # ————————60PerfectCRM实现CRM学生上课记录————————
410     stu_account = models.ForeignKey( "Customer", verbose_name='关联学员帐号', blank=True, null=True, on_delete=models.CASCADE,
411                                      help_text='报名成功后创建关联帐户' )
412     # ————————60PerfectCRM实现CRM学生上课记录————————
413 
414     def get_full_name(self):
415         return self.email
416     def get_short_name(self):
417         #用户确认的电子邮件地址
418         return self.email
419     def __str__(self):
420         return self.name
421     def has_perm(self,perm,obj=None):
422         #指明用户是否被认为活跃的。以反选代替删除帐号。
423         #最简单的可能的答案:是的,总是
424         return True   #有效 账号
425     def has_module_perms(self, app_label):
426         #指明用户是否可以登录到这个管理站点。
427         # 最简单的可能的答案:是的,总是
428         return True #职员状态
429     @property
430     def is_staff(self):
431         '''“用户的员工吗?”'''
432         #最简单的可能的答案:所有管理员都是员工
433         return self.is_superuser#是不是超级用户状态
434 # AUTH_USER_MODEL = 'crm.UserProfile'#使用自定的admin 表单   #settings.py
435 # ————————34PerfectCRM实现CRM自定义用户————————
436 # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
437     class Meta:
438         verbose_name_plural = '10CRM账户表'
439         permissions = (
440             ('crm_010101_all_table_data_list_GET', '010101_全部查看数据_GET'),
441             ('crm_010102_all_table_data_list_POST', '010102_全部查看数据_POST'),
442             ('crm_010103_all_table_add_GET', '010103_全部添加数据_GET'),
443             ('crm_010104_all_table_add_POST', '010104_全部添加数据_POST'),
444             ('crm_010105_all_table_change_GET', '010105_全部修改数据_GET'),
445             ('crm_010106_all_table_change_POST', '010106_全部修改数据_POST'),
446             ('crm_010107_all_table_delete_GET', '010107_全部删除数据_GET'),
447             ('crm_010108_all_table_delete_POST', '010108_全部删除数据_POST'),
448             ('crm_010109_all_password_reset_GET', '010109_全部密码重置_GET'),
449             ('crm_010110_all_password_reset_POST', '010110_全部密码重置_POST'),
450 
451             ('crm_010201_only_view_Branch_GET', '010201_只能查看校区表_GET'),
452             ('crm_010202_only_view_Branch_POST', '010202_只能查看校区表_POST'),
453             ('crm_010203_only_add_Branch_GET', '010203_只能添加校区表_GET'),
454             ('crm_010204_only_add_Branch_POST', '010204_只能添加校区表_POST'),
455             ('crm_010205_only_change_Branch_GET', '010205_只能修改校区表_GET'),
456             ('crm_010206_only_change_Branch_POST', '010206_只能修改校区表_POST'),
457             ('crm_010207_only_delete_Branch_GET', '010207_只能删除校区表_GET'),
458             ('crm_010208_only_delete_Branch_POST', '010208_只能删除校区表_POST'),
459 
460             ('crm_010301_only_view_ClassList_GET', '010301_只能查看班级表_GET'),
461             ('crm_010302_only_view_ClassList_POST', '010302_只能查看班级表_POST'),
462             ('crm_010303_only_add_ClassList_GET', '010303_只能添加班级表_GET'),
463             ('crm_010304_only_add_ClassList_POST', '010304_只能添加班级表_POST'),
464             ('crm_010305_only_change_ClassList_GET', '010305_只能修改班级表_GET'),
465             ('crm_010306_only_change_ClassList_POST', '010306_只能修改班级表_POST'),
466             ('crm_010307_only_delete_ClassList_GET', '010307_只能删除班级表_GET'),
467             ('crm_010308_only_delete_ClassList_POST', '010308_只能删除班级表_POST'),
468 
469             ('crm_010401_only_view_Course_GET', '010401_只能查看课程表_GET'),
470             ('crm_010402_only_view_Course_POST', '010402_只能查看课程表_POST'),
471             ('crm_010403_only_add_Course_GET', '010403_只能添加课程表_GET'),
472             ('crm_010404_only_add_Course_POST', '010404_只能添加课程表_POST'),
473             ('crm_010405_only_change_Course_GET', '010405_只能修改课程表_GET'),
474             ('crm_010406_only_change_Course_POST', '010406_只能修改课程表_POST'),
475             ('crm_010407_only_delete_Course_GET', '010407_只能删除课程表_GET'),
476             ('crm_010408_only_delete_Course_POST', '010408_只能删除课程表_POST'),
477 
478             ('crm_010501_only_view_Customer_GET', '010501_只能查看客户表_GET'),
479             ('crm_010502_only_view_Customer_POST', '010502_只能查看客户表_POST'),
480             ('crm_010503_only_add_Customer_GET', '010503_只能添加客户表_GET'),
481             ('crm_010504_only_add_Customer_POST', '010504_只能添加客户表_POST'),
482             ('crm_010505_only_change_Customer_GET', '010505_只能修改客户表_GET'),
483             ('crm_010506_only_change_Customer_POST', '010506_只能修改客户表_POST'),
484             ('crm_010507_only_delete_Customer_GET', '010507_只能删除客户表_GET'),
485             ('crm_010508_only_delete_Customer_POST', '010508_只能删除客户表_POST'),
486 
487             ('crm_010601_only_view_CustomerFollowUp_GET', '010601_只能查看跟进表_GET'),
488             ('crm_010602_only_view_CustomerFollowUp_POST', '010602_只能查看跟进表_POST'),
489             ('crm_010603_only_add_CustomerFollowUp_GET', '010603_只能添加跟进表_GET'),
490             ('crm_010604_only_add_CustomerFollowUp_POST', '010604_只能添加跟进表_POST'),
491             ('crm_010605_only_change_CustomerFollowUp_GET', '010605_只能修改跟进表_GET'),
492             ('crm_010606_only_change_CustomerFollowUp_POST', '010606_只能修改跟进表_POST'),
493             ('crm_010607_only_delete_CustomerFollowUp_GET', '010607_只能删除跟进表_GET'),
494             ('crm_010608_only_delete_CustomerFollowUp_POST', '010608_只能删除跟进表_POST'),
495 
496             ('crm_010701_only_view_Enrollment_GET', '010701_只能查看报名表_GET'),
497             ('crm_010702_only_view_Enrollment_POST', '010702_只能查看报名表_POST'),
498             ('crm_010703_only_add_Enrollment_GET', '010703_只能添加报名表_GET'),
499             ('crm_010704_only_add_Enrollment_POST', '010704_只能添加报名表_POST'),
500             ('crm_010705_only_change_Enrollment_GET', '010705_只能修改报名表_GET'),
501             ('crm_010706_only_change_Enrollment_POST', '010706_只能修改报名表_POST'),
502             ('crm_010707_only_delete_Enrollment_GET', '010707_只能删除报名表_GET'),
503             ('crm_010708_only_delete_Enrollment_POST', '010708_只能删除报名表_POST'),
504 
505             ('crm_010801_only_view_Payment_GET', '010801_只能查看缴费表_GET'),
506             ('crm_010802_only_view_Payment_POST', '010802_只能查看缴费表_POST'),
507             ('crm_010803_only_add_Payment_GET', '010803_只能添加缴费表_GET'),
508             ('crm_010804_only_add_Payment_POST', '010804_只能添加缴费表_POST'),
509             ('crm_010805_only_change_Payment_GET', '010805_只能修改缴费表_GET'),
510             ('crm_010806_only_change_Payment_POST', '010806_只能修改缴费表_POST'),
511             ('crm_010807_only_delete_Payment_GET', '010807_只能删除缴费表_GET'),
512             ('crm_010808_only_delete_Payment_POST', '010808_只能删除缴费表_POST'),
513 
514             ('crm_010901_only_view_CourseRecord_GET', '010901_只能查看上课表_GET'),
515             ('crm_010902_only_view_CourseRecord_POST', '010902_只能查看上课表_POST'),
516             ('crm_010903_only_add_CourseRecord_GET', '010903_只能添加上课表_GET'),
517             ('crm_010904_only_add_CourseRecord_POST', '010904_只能添加上课表_POST'),
518             ('crm_010905_only_change_CourseRecord_GET', '010905_只能修改上课表_GET'),
519             ('crm_010906_only_change_CourseRecord_POST', '010906_只能修改上课表_POST'),
520             ('crm_010907_only_delete_CourseRecord_GET', '010907_只能删除上课表_GET'),
521             ('crm_010908_only_delete_CourseRecord_POST', '010908_只能删除上课表_POST'),
522 
523             ('crm_011001_only_view_StudyRecord_GET', '011001_只能查看学习表_GET'),
524             ('crm_011002_only_view_StudyRecord_POST', '011002_只能查看学习表_POST'),
525             ('crm_011003_only_add_StudyRecord_GET', '011003_只能添加学习表_GET'),
526             ('crm_011004_only_add_StudyRecord_POST', '011004_只能添加学习表_POST'),
527             ('crm_011005_only_change_StudyRecord_GET', '011005_只能修改学习表_GET'),
528             ('crm_011006_only_change_StudyRecord_POST', '011006_只能修改学习表_POST'),
529             ('crm_011007_only_delete_StudyRecord_GET', '011007_只能删除学习表_GET'),
530             ('crm_011008_only_delete_StudyRecord_POST', '011008_只能删除学习表_POST'),
531 
532             ('crm_011101_only_view_UserProfile_GET', '011101_只能查看账号表_GET'),
533             ('crm_011102_only_view_UserProfile_POST', '011102_只能查看账号表_POST'),
534             ('crm_011103_only_add_UserProfile_GET', '011103_只能添加账号表_GET'),
535             ('crm_011104_only_add_UserProfile_POST', '011104_只能添加账号表_POST'),
536             ('crm_011105_only_change_UserProfile_GET', '011105_只能修改账号表_GET'),
537             ('crm_011106_only_change_UserProfile_POST', '011106_只能修改账号表_POST'),
538             ('crm_011107_only_delete_UserProfile_GET', '011107_只能删除账号表_GET'),
539             ('crm_011108_only_delete_UserProfile_POST', '011108_只能删除账号表_POST'),
540 
541             ('crm_011201_only_view_Role_GET', '011201_只能查看角色表_GET'),
542             ('crm_011202_only_view_Role_POST', '011202_只能查看角色表_POST'),
543             ('crm_011203_only_add_Role_GET', '011203_只能添加角色表_GET'),
544             ('crm_011204_only_add_Role_POST', '011204_只能添加角色表_POST'),
545             ('crm_011205_only_change_Role_GET', '011205_只能修改角色表_GET'),
546             ('crm_011206_only_change_Role_POST', '011206_只能修改角色表_POST'),
547             ('crm_011207_only_delete_Role_GET', '011207_只能删除角色表_GET'),
548             ('crm_011208_only_delete_Role_POST', '011208_只能删除角色表_POST'),
549 
550             ('crm_011301_only_view_Tag_GET', '011301_只能查看标签表_GET'),
551             ('crm_011302_only_view_Tag_POST', '011302_只能查看标签表_POST'),
552             ('crm_011303_only_add_Tag_GET', '011303_只能添加标签表_GET'),
553             ('crm_011304_only_add_Tag_POST', '011304_只能添加标签表_POST'),
554             ('crm_011305_only_change_Tag_GET', '011305_只能修改标签表_GET'),
555             ('crm_011306_only_change_Tag_POST', '011306_只能修改标签表_POST'),
556             ('crm_011307_only_delete_Tag_GET', '011307_只能删除标签表_GET'),
557             ('crm_011308_only_delete_Tag_POST', '011308_只能删除标签表_POST'),
558 
559             ('crm_011401_only_view_FirstLayerMenu_GET', '011401_只能查看一层菜单_GET'),
560             ('crm_011402_only_view_FirstLayerMenu_POST', '011402_只能查看一层菜单_POST'),
561             ('crm_011403_only_add_FirstLayerMenu_GET', '011403_只能添加一层菜单_GET'),
562             ('crm_011404_only_add_FirstLayerMenu_POST', '011404_只能添加一层菜单_POST'),
563             ('crm_011405_only_change_FirstLayerMenu_GET', '011405_只能修改一层菜单_GET'),
564             ('crm_011406_only_change_FirstLayerMenu_POST', '011406_只能修改一层菜单_POST'),
565             ('crm_011407_only_delete_FirstLayerMenu_GET', '011407_只能删除一层菜单_GET'),
566             ('crm_011408_only_delete_FirstLayerMenu_POST', '011408_只能删除一层菜单_POST'),
567 
568             ('crm_011501_only_view_SubMenu_GET', '011501_只能查看二层菜单_GET'),
569             ('crm_011502_only_view_SubMenu_POST', '011502_只能查看二层菜单_POST'),
570             ('crm_011503_only_add_SubMenu_GET', '011503_只能添加二层菜单_GET'),
571             ('crm_011504_only_add_SubMenu_POST', '011504_只能添加二层菜单_POST'),
572             ('crm_011505_only_change_SubMenu_GET', '011505_只能修改二层菜单_GET'),
573             ('crm_011506_only_change_SubMenu_POST', '011506_只能修改二层菜单_POST'),
574             ('crm_011507_only_delete_SubMenu_GET', '011507_只能删除二层菜单_GET'),
575             ('crm_011508_only_delete_SubMenu_POST', '011508_只能删除二层菜单_POST'),
576 
577             ('crm_011601_only_view_Groups_GET', '011601_只能查看权限组_GET'),
578             ('crm_011602_only_view_Groups_POST', '011602_只能查看权限组_POST'),
579             ('crm_011603_only_add_Groups_GET', '011603_只能添加权限组_GET'),
580             ('crm_011604_only_add_Groups_POST', '011604_只能添加权限组_POST'),
581             ('crm_011605_only_change_Groups_GET', '011605_只能修改权限组_GET'),
582             ('crm_011606_only_change_Groups_POST', '011606_只能修改权限组_POST'),
583             ('crm_011607_only_delete_Groups_GET', '011607_只能删除权限组_GET'),
584             ('crm_011608_only_delete_Groups_POST', '011608_只能删除权限组_POST'),
585 
586             ('crm_011701_own_password_reset_GET', '011701_自己密码重置_GET'),
587             ('crm_011702_own_password_reset_POST', '011702_自己密码重置_POST'),
588 
589             ('crm_020101_all_not_audit_GET', '020101_销售查看全部的客户未审核_GET'),
590             ('crm_020103_all_enrollment_GET', '020103_销售给全部的客户报名课程_GET'),
591             ('crm_020104_all_enrollment_POST', '020104_销售给全部的客户报名课程_POST'),
592             ('crm_020105_all_contract_review_GET', '020105_销售给全部的客户审核合同_GET'),
593             ('crm_020116_all_contract_review_POST', '020116_销售给全部的客户审核合同_POST'),
594 
595             ('crm_020201_own_enrollment_GET', '020201_销售给自己的客户报名课程_GET'),
596             ('crm_020202_own_enrollment_POST', '020202_销售给自己的客户报名课程_POST'),
597             ('crm_020203_own_contract_review_GET', '020203_销售给自己的客户审核合同_GET'),
598             ('crm_020204_own_contract_review_POST', '020204_销售给自己的客户审核合同_POST'),
599 
600             ('crm_030101_all_not_payment_GET', '030101_财务查看全部的客户未缴费_GET'),
601             ('crm_030102_all_not_payment_POST', '030102_财务查看全部的客户未缴费_POST'),
602             ('crm_030103_all_already_payment_GET', '030103_财务查看全部的客户已缴费_GET'),
603             ('crm_030104_all_already_payment_POST', '030104_财务查看全部的客户已缴费_POST'),
604             ('crm_030105_all_payment_GET', '030105_财务进行全部的客户缴费_GET'),
605             ('crm_030106_all_payment_POST', '030106_财务进行全部的客户缴费_POST'),
606 
607             ('crm_040101_own_student_course_GET', '040101_学生查看自己的课程_GET'),
608             ('crm_040102_own_student_course_POST', '040102_学生查看自己的课程_POST'),
609             ('crm_040103_own_studyrecords_GET', '040103_学生自己的上课记录_GET'),
610             ('crm_040104_own_studyrecords_POST', '040104_学生自己的上课记录_POST'),
611             ('crm_040105_own_homework_detail_GET', '040105_学生自己的作业详情_GET'),
612             ('crm_040106_own_homework_detail_POST', '040106_学生自己的作业详情_POST'),
613 
614             ('crm_050101_own_teacher_class_GET', '050101_讲师查看自己的班级_GET'),
615             ('crm_050102_own_teacher_class_POST', '050102_讲师查看自己的班级_POST'),
616             ('crm_050103_own_teacher_class_detail_GET', '050103_讲师查看自己的课节详情_GET'),
617             ('crm_050104_own_teacher_class_detail_POST', '050104_讲师查看自己的课节详情_POST'),
618             ('crm_050105_own_teacher_lesson_detail_GET', '050105_讲师查看自己的课节学员_GET'),
619             ('crm_050106_own_teacher_lesson_detail_POST', '050106_讲师查看自己的课节学员_POST'),
620             ('crm_050107_own_howk_down_GET', '050107_讲师自己的学员作业下载_GET'),
621             ('crm_050108_own_howk_down_POST', '050108_讲师自己的学员作业下载_POST'),
622 
623             ('crm_060101_own_coursetop_details_GET', '060101_讲师查看自己的班级排名详情_GET'),
624             ('crm_060102_own_coursetop_details_POST', '060102_讲师查看自己的班级排名详情_POST'),
625             ('crm_060103_own_coursetop_score_GET', '060103_讲师查看自己的班级分数排行_GET'),
626             ('crm_060104_own_coursetop_score_POST', '060104_讲师查看自己的班级排分数排行_POST'),
627             ('crm_060105_own_coursetop_homework_GET', '060105_讲师查看自己的班级作业排行_GET'),
628             ('crm_060106_own_coursetop_homework_POST', '060106_讲师查看自己的班级作业排行_POST'),
629             ('crm_060107_own_coursetop_attendance_GET', '060107_讲师查看自己的班级出勤排行_GET'),
630             ('crm_060108_own_coursetop_attendance_POST', '060108_讲师查看自己的班级出勤排行_POST'),
631 
632         )
633 # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
634 # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
635 """15权限组"""
636 from django.contrib.auth.models import Group
637 class Groups(Group):
638     class Meta:
639         verbose_name_plural = '15权限组'
640 # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
641 # ————————75PerfectCRM实现CRM扩展权限————————
642 from django.contrib.auth.models import Permission
643 class Permissions(Permission):
644     dic_name = models.CharField(_('dic_name'), max_length=255)
645     class Meta:
646         verbose_name_plural = "16扩展权限"
647 # ————————75PerfectCRM实现CRM扩展权限————————
648 
649 
650 """11角色表"""
651 class Role(models.Model):
652     name = models.CharField(unique=True,max_length=32)#角色名#CharField定长文本#角色名不可以重复#最长度=32字节
653 
654     # ————————72PerfectCRM实现CRM动态菜单和角色————————
655     menus = models.ManyToManyField('FirstLayerMenu',verbose_name='一层菜单',blank=True)
656     # ————————72PerfectCRM实现CRM动态菜单和角色————————
657 
658     def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
659         return self.name#返回 #角色名
660     class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据
661         verbose_name_plural = "11角色表" #verbose_name_plural给你的模型类起一个更可读的名字
662 
663 
664 """12标签表"""
665 class Tag(models.Model):
666     name =  models.CharField(max_length=64,unique=True) #标签名#CharField定长文本#最长度=64字节#不可以重复
667     def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
668         return self.name #返回 #标签名
669     class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
670         verbose_name_plural =  "12标签表" #verbose_name_plural给你的模型类起一个更可读的名字
671 
672 # ————————01PerfectCRM基本配置ADMIN————————
673 
674 
675 # ————————72PerfectCRM实现CRM动态菜单和角色————————
676 """13一层菜单名"""
677 class FirstLayerMenu(models.Model):
678     '''第一层侧边栏菜单'''
679     name = models.CharField('一层菜单名',max_length=64)
680     url_type_choices = ((0,'相关的名字'),(1,'固定的URL'))
681     url_type = models.SmallIntegerField(choices=url_type_choices,default=0)
682     url_name = models.CharField(max_length=64,verbose_name='一层菜单路径')
683     order = models.SmallIntegerField(default=0,verbose_name='菜单排序')
684     sub_menus = models.ManyToManyField('SubMenu',blank=True)
685 
686     def __str__(self):
687         return self.name
688 
689     class Meta:
690         verbose_name_plural = "13第一层菜单"
691 
692 """14二层菜单名"""
693 class SubMenu(models.Model):
694     '''第二层侧边栏菜单'''
695     name = models.CharField('二层菜单名', max_length=64)
696     url_type_choices = ((0,'相关的名字'),(1,'固定的URL'))
697     url_type = models.SmallIntegerField(choices=url_type_choices,default=0)
698     url_name = models.CharField(max_length=64, verbose_name='二层菜单路径')
699     order = models.SmallIntegerField(default=0, verbose_name='菜单排序')
700 
701     def __str__(self):
702         return self.name
703 
704     class Meta:
705         verbose_name_plural = "14第二层菜单"
706 # ————————72PerfectCRM实现CRM动态菜单和角色————————
#models.py

 

 

 

 

  1 # kingadmin.py
  2 # ————————04PerfectCRM实现King_admin注册功能————————
  3 from crm import models
  4 #print("kingadmin crm",models.Customer)
  5 
  6 # ————————05PerfectCRM实现King_admin注册功能获取内存————————
  7 # from king_admin.base_admin import register,BaseAdmin
  8 from king_admin.base_admin import site,BaseAdmin
  9 # ————————05PerfectCRM实现King_admin注册功能获取内存————————
 10 
 11 # ————————24PerfectCRM实现King_admin自定义操作数据————————
 12 from django.shortcuts import render
 13 # ————————24PerfectCRM实现King_admin自定义操作数据————————
 14 
 15 # ————————28PerfectCRM实现King_admin编辑限制————————
 16 from django.forms import ValidationError
 17 from django.shortcuts import render,redirect
 18 # ————————28PerfectCRM实现King_admin编辑限制————————
 19 
 20 
 21 
 22 
 23 # ————————62PerfectCRM实现CRM讲师讲课记录————————
 24 # 02班级表
 25 class ClassListAdmin(BaseAdmin):
 26     list_display = ['id', 'branch', 'course', 'class_type', 'semester', 'start_date', 'end_date']  # 显示字段表头
 27     list_filter = ['branch', 'course', 'class_type']  # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
 28     filter_horizontal = ['teachers']  #复选框
 29 site.register(models.ClassList,ClassListAdmin)               #02班级表
 30 
 31 # ————————62PerfectCRM实现CRM讲师讲课记录————————
 32 
 33 
 34 
 35 
 36 #04客户信息表
 37 class CustomerAdmin(BaseAdmin):#定制Djanago admin
 38     # ————————54PerfectCRM实现CRM客户报名链接————————
 39     # list_display = ('id', 'qq', 'source', 'consultant', 'content', 'date')  # 显示字段表头
 40     list_display = ('id', 'qq', 'source', 'consultant', 'content', 'date','status','enroll')  # 显示字段表头
 41     # ————————54PerfectCRM实现CRM客户报名链接————————
 42     # ————————11PerfectCRM实现King_admin分页显示条数————————
 43     list_per_page = 2  #分页条数  # 默认分页条数10
 44     # ————————11PerfectCRM实现King_admin分页显示条数————————
 45     # ————————16PerfectCRM实现King_admin日期过滤————————
 46     # ————————15PerfectCRM实现King_admin多条件过滤————————
 47     # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
 48     # list_filter = ('source','consultant','consult_courses',)
 49     list_filter = ('date','source','consultant','consult_courses',)
 50     # ————————15PerfectCRM实现King_admin多条件过滤————————
 51     # ————————16PerfectCRM实现King_admin日期过滤————————
 52     # ————————18PerfectCRM实现King_admin搜索关键字————————
 53     #搜索(不能包含CharField)(注意加 逗号 , )
 54     search_fields = ('name','qq',)
 55     # ————————18PerfectCRM实现King_admin搜索关键字————————
 56     # ————————26PerfectCRM实现King_admin自定义排序————————
 57     ordering = '-qq'  #自定义排序,默认'-id'
 58     # ————————26PerfectCRM实现King_admin自定义排序————————
 59     # ————————27PerfectCRM实现King_admin编辑复选框————————
 60     filter_horizontal = ('tags',) #复选框
 61     # ————————27PerfectCRM实现King_admin编辑复选框————————
 62     # ————————33PerfectCRM实现King_admin编辑整张表限制————————
 63     readonly_table=True#默认表单不锁定
 64     # ————————33PerfectCRM实现King_admin编辑整张表限制————————
 65 
 66     # ————————55PerfectCRM实现CRM客户报名状态颜色变化————————
 67     colored_fields = {
 68         'status':{'已报名':"rgba(145, 255, 0, 0.78)",
 69                   '未报名':"#ddd"},}
 70     # ————————55PerfectCRM实现CRM客户报名状态颜色变化————————
 71 
 72     # ————————54PerfectCRM实现CRM客户报名链接————————
 73     def enroll(self):
 74         '''报名'''
 75         print("customize field enroll",self)
 76         link_name = "报名"
 77         if self.instance.status == 0:
 78             link_name = "报名新课程"
 79         return '''<a target="_blank" class="btn-link" href="/bpm/customer/%s/enrollment/">点击%s</a> ''' % (self.instance.id,link_name)
 80                 # url(r'^customer/(\d+)/enrollment/$', sales_views.enrollment, name="enrollment"),  # 客户招生#报名流程一 下一步
 81                 # target属性用于表示所链接文件打开到的位置 #记住,“”内的文字只是表示一个对象的名子。
 82     enroll.display_name = "报名链接"
 83     # ————————54PerfectCRM实现CRM客户报名链接————————
 84 
 85 
 86 
 87     # ————————24PerfectCRM实现King_admin自定义操作数据————————
 88     # from django.shortcuts import render
 89     actions = ['test_actions',]#定制功能    #测试返回到一个新页面
 90     def test_actions(self,request,arg2):#对应的函数 #request类自己的请求  #arg2类的内容
 91         return render(request,"king_admin/table_index.html")
 92     test_actions.short_description = "测试显示中文"
 93     # ————————24PerfectCRM实现King_admin自定义操作数据————————
 94 
 95     # ————————28PerfectCRM实现King_admin编辑限制————————
 96     # ————————31PerfectCRM实现King_admin编辑多对多限制————————
 97     # readonly_fields = ('qq', 'consultant',)  # 不可修改
 98     readonly_fields = ('qq', 'consultant','tags',)  # 不可修改
 99     # ————————31PerfectCRM实现King_admin编辑多对多限制————————
100 
101     # ————————29PerfectCRM实现King_admin编辑自定义限制————————
102     def default_form_validation(self,obj):
103         print('validation:制定的',obj.cleaned_data)
104         consult_course=obj.cleaned_data.get('content','')#自制验证字段
105         if len(consult_course)<10:
106             return ValidationError(#添加错误信息 返回
107                                 ("该字段%(field)s 咨询内容记录不能少于10个字符"),
108                                 code='invalid',
109                                 params={'field':'content',},
110                             )
111     # ————————29PerfectCRM实现King_admin编辑自定义限制————————
112 
113     # ————————28PerfectCRM实现King_admin编辑限制————————
114 
115     # ————————30PerfectCRM实现King_admin编辑自定义字段验证————————
116     def clean_name(self,obj,*args,**kwargs):#名称验证 单个
117         name=obj.cleaned_data['name']
118         if not name:
119             obj.add_error('name','不能为空!')
120             return ValidationError(#添加错误信息 返回
121                                 ("%(field)s:该字段 不能为空"),
122                                 code='invalid',
123                                 params={'field':'name',},
124                             )
125         elif len(name)<5:
126             obj.add_error('name','不能小于5个字符!')
127             #return ValidationError('',)
128             return ValidationError(#添加错误信息 返回
129                                 ("%(field)s:该字段 不能小于5个字符!"),
130                                 code='invalid',
131                                 params={'field':'name',},
132                             )
133     # ————————30PerfectCRM实现King_admin编辑自定义字段验证————————
134 
135 # ————————34PerfectCRM实现CRM自定义用户————————
136 #10账号表
137 class UserProfileAdmin(BaseAdmin):#定制Djanago admin
138     list_display = ('id', 'email', 'name')  # 显示字段表头
139 
140     # ————————36PerfectCRM实现King_admin密码修改————————
141     readonly_fields = ('password',)   # 不可修改,限制
142 
143     # ————————72PerfectCRM实现CRM动态菜单和角色————————
144     # filter_horizontal = ('user_permissions','groups') #复选框
145     filter_horizontal = ('user_permissions', 'groups','roles')  # 复选框
146     # ————————72PerfectCRM实现CRM动态菜单和角色————————
147 
148     modelform_exclude_fields=['last_login']#排除#不显示 #自增日期 #base_admin.py #forms.py
149     # ————————36PerfectCRM实现King_admin密码修改————————
150 
151 site.register(models.UserProfile, UserProfileAdmin)
152 # ————————34PerfectCRM实现CRM自定义用户————————
153 
154 # ————————05PerfectCRM实现King_admin注册功能获取内存————————
155 # register(models.Customer,CustomerAdmin)
156 # register(models.CourseRecord)
157 site.register(models.Customer,CustomerAdmin)
158 # ————————58PerfectCRM实现king_admin批量生成上课记录————————
159 # site.register(models.CourseRecord)
160 # ————————58PerfectCRM实现king_admin批量生成上课记录————————
161 # ————————05PerfectCRM实现King_admin注册功能获取内存————————
162 
163 # ————————04PerfectCRM实现King_admin注册功能————————
164 
165 
166 # ————————56PerfectCRM实现CRM客户报名缴费链接————————
167 # 06学员报名信息表
168 class EnrollmentAdmin(BaseAdmin):  # 定制Djanago admin
169     list_display = ('id', 'customer', 'enrolled_class', 'consultant', 'Pay_cost', 'date', 'payment')  # 显示字段表头
170 
171     # ————————58PerfectCRM实现king_admin批量生成上课记录————————
172     list_filter = ('enrolled_class','consultant', 'Pay_cost',) # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
173     # ————————58PerfectCRM实现king_admin批量生成上课记录————————
174 
175     colored_fields = {
176         'Pay_cost': {True: "rgba(145, 255, 0, 0.78)",
177                      False: "#ddd"}, }
178     def payment(self):
179         link_name = "增加缴费"
180         if self.instance.Pay_cost == False:
181             link_name = "缴费"
182         return '''<a target="_blank" class="btn-link"  href="/bpm/payment/%s/" >点击%s</a> ''' % (self.instance.id, link_name)
183         # url(r'^payment/(\d+)/$', financial_views.payment, name="payment"),  # 报名流程四    缴费   #财务
184         # target属性用于表示所链接文件打开到的位置 #记住,“”内的文字只是表示一个对象的名子。
185     payment.display_name = "缴费链接"
186 site.register(models.Enrollment, EnrollmentAdmin)  # 06学员报名信息表
187 # ————————56PerfectCRM实现CRM客户报名缴费链接————————
188 
189 # ————————58PerfectCRM实现king_admin批量生成上课记录————————
190 # 07缴费记录表
191 class PaymentAdmin(BaseAdmin):
192     list_display = ['id', 'customer', 'course', 'amount', 'consultant','date']  # 显示字段表头
193     list_filter = ('customer', 'course', 'consultant',)  # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
194 
195 from django.shortcuts import render, HttpResponse, redirect
196 # 08每节课上课纪录表
197 class CourseRecordAdmin(BaseAdmin):
198     list_display = ['id', 'from_class', 'day_num', 'teacher', 'has_homework', 'homework_title', 'homework_content','outline', 'date']  # 显示字段表头
199     list_filter = ('from_class', 'teacher', 'date')  # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
200     def initialize_studyrecords(self, request, queryset):  # 制定功能
201         print('initialize_studyrecords', self, request, queryset)
202         if len(queryset) > 1:
203             return HttpResponse("同时只能选择一个班级!")
204         print('获取对应的学员', queryset[0].from_class.enrollment_set.all())  # _set反向查询
205         new_obj_list = []  # 用于批量创建事务  #防止数据库事物回滚
206         for enrll_obj in queryset[0].from_class.enrollment_set.all():  # 创建学习记录
207             #     models.StudyRecord.objects.get_or_create(       #get_or_ #防止报错
208             #         student=enrll_obj,#对应学员
209             #         course_record=queryset[0],
210             #         attendance=0,#签到状态,默认签到,
211             #         score=0,#成绩
212             #     )
213 
214             # 防止数据库事物回滚    #"""09学习纪录"""
215             new_obj_list.append(models.StudyRecord(
216                 student=enrll_obj,  # 对应学员
217                 course_record=queryset[0],  # 班级#节课
218                 attendance=0,  # 签到状态,默认签到,
219                 score=0,  # 成绩
220             ))
221         try:
222             models.StudyRecord.objects.bulk_create(new_obj_list)  # bulk_create批量创建数据库事物 #统一最后保存
223         except Exception as e:
224             return HttpResponse('批量创建失败,本节课可能有相应的上课记录')
225 
226         return redirect("/king_admin/crm/studyrecord/?course_record=%s" % queryset[0].id)  # 学习记录 #加上过滤
227 
228     actions = ['initialize_studyrecords', ]
229     initialize_studyrecords.short_description = "创建班级本节上课记录"  # 显示别名
230 # 09学习纪录
231 class StudyRecordAdmin(BaseAdmin):
232     list_display = ['id', 'student', 'course_record', 'attendance', 'score', 'date']  # 显示字段表头
233 
234     list_filter = ['course_record', 'attendance', 'score', 'student']  # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
235 
236     list_editable = ['score', 'attendance']  # 可编辑   #用于上课点名 批改成绩
237 
238 site.register(models.Payment, PaymentAdmin)  # 07缴费记录表
239 site.register(models.CourseRecord, CourseRecordAdmin)  # 08每节课上课纪录表
240 site.register(models.StudyRecord, StudyRecordAdmin)  # 09学习纪录
241 # ————————58PerfectCRM实现king_admin批量生成上课记录————————
242 
243 
244 # ————————72PerfectCRM实现CRM动态菜单和角色————————
245 # 11角色表
246 class RoleAdmin(BaseAdmin):
247     list_display = ['id', 'name']  # 显示字段表头
248     filter_horizontal = ['menus']  # 复选框
249 site.register(models.Role,RoleAdmin) #11角色表
250 
251 # 13一层菜单名
252 class FirstLayerMenuAdmin(BaseAdmin):
253     list_display = ['id', 'name', 'url_type', 'url_name', 'order']  # 显示字段表头
254 site.register(models.FirstLayerMenu,FirstLayerMenuAdmin)  #13一层菜单名
255 # 14二层菜单名
256 class SubMenuMenuAdmin(BaseAdmin):
257     list_display = ['id', 'name', 'url_type', 'url_name', 'order']  # 显示字段表头
258 site.register(models.SubMenu,SubMenuMenuAdmin)   #14二层菜单名
259 # ————————72PerfectCRM实现CRM动态菜单和角色————————
260 
261 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL————————
262 class GroupsAdmin(BaseAdmin):
263     list_display = ['id', 'name']  # 显示字段表头
264     filter_horizontal = ['permissions']  # 复选框
265 site.register(models.Groups,GroupsAdmin)   #14二层菜单名
266 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL————————
267 
268 # ————————75PerfectCRM实现CRM扩展权限————————
269 class PermissionsAdmin(BaseAdmin):
270     list_display = ['id', 'name','codename','dic_name']  # 显示字段表头
271 site.register(models.Permissions,PermissionsAdmin)   #16扩展权限
272 # ————————75PerfectCRM实现CRM扩展权限————————
# kingadmin.py

 

 

 

  1 # permission.py
  2 # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
  3 from django.urls import resolve # resolve解析URL
  4 from django.shortcuts import render,redirect,HttpResponse #页面返回
  5 from permissions.permission_list import perm_dic #权限字典
  6 # ————————75PerfectCRM实现CRM扩展权限————————
  7 import json #字符串转列表
  8 from crm import models #数据库查询扩展的权限
  9 from permissions.ECJ import * #扩展的自定义函数
 10 # ————————75PerfectCRM实现CRM扩展权限————————
 11 def perm_check(*args,**kwargs):
 12     print( '执行perm_check:', *args, **kwargs )
 13     request = args[0]#
 14     # print(request) #<WSGIRequest: GET '/king_admin/crm/firstlayermenu/4/change/'>
 15 
 16     resolve_url_obj = resolve(request.path)#反解URL路径#获取当前的URL# resolve解析URL#生成实例
 17     print('反解URL路径:',resolve_url_obj)#ResolverMatch(func=permissions.permission.inner, args=('crm', 'firstlayermenu', '4'), kwargs={}, url_name=table_change, app_names=[], namespaces=[])
 18     current_url_name = resolve_url_obj.url_name  # 当前url的url_name
 19     print('当前用户:',request.user,'当前url的url_name:',current_url_name)#admin2 当前url的url_name: table_change
 20 
 21     permission_list= request.user.user_permissions.values_list('codename') # 根据 登陆的ID 获取 拥有的权限列表
 22     print('拥有的权限列表',permission_list)
 23 
 24     permission_group = request.user.groups.all().values_list('permissions__codename')    # 根据 登陆的ID 获取 拥有的组
 25     print('拥有的权限组',permission_group)
 26 
 27     match_key = None
 28     match_results = [False,] #后面会覆盖,加个False是为了让all(match_results)不出错
 29 
 30     # ————————75PerfectCRM实现CRM扩展权限————————
 31     print('permission_list',perm_dic) #permission_list
 32     models_dic = dict(models.Permissions.objects.values_list( 'codename', 'dic_name' ))#查询数据库
 33     print( 'models_dic', models_dic )
 34     perm_dic.update(models_dic) #扩展权限字典
 35     print( '扩展后的权限字典', perm_dic )
 36     # ————————75PerfectCRM实现CRM扩展权限————————
 37 
 38     for permission_key,permission_val in  perm_dic.items():#从权限字典中取相关字段 #crm_table_index':['1','table_index','GET',[],{},],
 39         # print('循环权限表',((permission_key),))
 40         if ((permission_key),) in permission_list or ((permission_key),) in permission_group:#权限列表是元组
 41             # ————————75PerfectCRM实现CRM扩展权限————————
 42             if type( permission_val ).__name__ in ['str']:
 43                 permission_val = json.loads( permission_val )  # 字符串转列表
 44             # ————————75PerfectCRM实现CRM扩展权限————————
 45 
 46             per_url_name = permission_val[0] #URL
 47             per_method  = permission_val[1] #GET #POST #请求方法
 48             perm_args = permission_val[2]  # 列表参数
 49             perm_kwargs = permission_val[3]# 字典参数
 50 
 51             # ————————75PerfectCRM实现CRM扩展权限————————
 52             # custom_perm_func = None if len(permission_val) == 4 else permission_val[4] #url判断 #自定义权限钩子
 53             if len( permission_val ) == 4 :
 54                 custom_perm_func = None
 55             else:
 56                 if type( permission_val[4] ).__name__ in ['str']:
 57                     custom_perm_func = globals().get( permission_val[4] )  # url判断 #自定义权限钩子
 58                 else:
 59                     custom_perm_func = permission_val[4]
 60             # ————————75PerfectCRM实现CRM扩展权限————————
 61 
 62             # 'crm_can_access_my_clients':['table_list','GET',[],{'perm_check':33,'arg2':'test'}, custom_perm_logic.only_view_own_customers],
 63             # print('URL:',per_url_name,'请求方法:',per_method,'列表参数:',perm_args,'字典参数:',perm_kwargs,'自定义权限钩子:',custom_perm_func)
 64 
 65 
 66             if per_url_name == current_url_name: #权限字典的 URL  ==当前请求的url #crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
 67                 if per_method == request.method: #权限字典的 请求方法 == 当前请求的方法  #crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
 68                     #逐个匹配参数,看每个参数时候都能对应的上。
 69                     args_matched = False #参数匹配 #仅供参数
 70                     for item in perm_args: #循环列表参数 #crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
 71                         request_method_func = getattr(request,per_method) #反射 #请求方法 #GET #POST
 72                         if request_method_func.get(item,None):# 如果request字典中有此参数
 73                             args_matched = True
 74                         else:
 75                             print("参数不匹配......")
 76                             args_matched = False
 77                             break  # 有一个参数不能匹配成功,则判定为假,退出该循环。
 78                     else:
 79                         args_matched = True #没有执行 break 表示 列表匹配成功 #防止列表没有使用参数时出错
 80 
 81                     #匹配有特定值的参数
 82                     kwargs_matched = False
 83                     for k,v in perm_kwargs.items(): #循环字典参数#crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
 84                         request_method_func = getattr(request, per_method) #反射 #请求方法 #GET #POST
 85                         arg_val = request_method_func.get(k, None)  # request字典中有此参数
 86                         print("perm kwargs check:",arg_val,type(arg_val),v,type(v))
 87                         if arg_val == str(v): #匹配上了特定的参数 及对应的 参数值, 比如,需要request 对象里必须有一个叫 user_id=3的参数
 88                             kwargs_matched = True
 89                         else:
 90                             kwargs_matched = False
 91                             break # 有一个参数不能匹配成功,则判定为假,退出该循环。
 92                     else:
 93                         kwargs_matched = True
 94 
 95 
 96                     #自定义权限钩子
 97                     perm_func_matched = False
 98                     if custom_perm_func: #如果有定义
 99                         if custom_perm_func(request,args,kwargs):#def only_view_own_customers(request,*args,**kwargs):
100                             perm_func_matched = True
101                         else:
102                             perm_func_matched = False #使整条权限失效
103                             print('自定义权限钩子没有通过',perm_func_matched)
104                     else: #没有定义权限钩子,所以默认通过
105                         perm_func_matched = True
106 
107                     match_results = [args_matched,kwargs_matched,perm_func_matched] #列表
108                     print("匹配结果: ", match_results) # [True, True, True]
109                     if all(match_results): #都匹配上了 #都返回 True
110                         match_key = permission_key # 给 match_key = None 赋值
111                         break  #跳出大循环
112 
113     if all(match_results): #如果都匹配成功     #'crm_table_index':['table_index','GET',[],{},],
114         app_name, *per_name = match_key.split('_') #先给app_name赋一个值,其他的值都给*per_name     'crm_table_index':
115         print("权限名:",match_key,'权限:',match_results)#crm_010902_only_view_CourseRecord_POST [True, True, True]
116         print('分割:',app_name, *per_name) #  crm 010902 only view CourseRecord POST
117         perm_obj = '%s.%s' % (app_name,match_key)#'crm.table_index' #    url(r'^(\w+)/$', views.table_index, name='table_index'),  # 单个具体app页面
118         print("生成权限:",perm_obj) #crm.crm_010902_only_view_CourseRecord_POST
119         if request.user.has_perm(perm_obj):
120             print('当前用户有此权限')
121             return True
122         else:
123             print('当前用户没有该权限')
124             return False
125     else:
126         print("未匹配到权限项,当前用户无权限")
127 
128 def check_permission(func):
129     print('权限func',func)#权限func <function table_data_list at 0x030636A8> #循环 URL name
130     def inner(*args,**kwargs):
131         print('开始权限匹配:',type(args))
132         request = args[0]#请求第一个
133         print('判断登陆情况:')
134         if request.user.id == None:
135             print('未登陆')
136             return redirect( '/gbacc/gbacc_login/' )#返回登陆页面
137         else:
138             if request.user.is_superuser == True:
139                 print('超级管理员')
140                 return func( *args, **kwargs )  #直接返回 真
141             print( '已登陆,判断有perm_check(*args,**kwargs)去执行' )
142             if not perm_check(*args,**kwargs): #如果返回不为真 #没权限
143                 print('#没权限',perm_check(*args,**kwargs))
144                 request = args[0]
145                 return HttpResponse('你没有这个权限')
146             print('有权限',func(*args,**kwargs)) #<HttpResponse status_code=200, "text/html; charset=utf-8">
147             return func(*args,**kwargs)
148     print('inner',inner)
149     return  inner #返回 真或假
150 # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
# permission.py

 

 

 

 1 # ECJ.py
 2 # ————————75PerfectCRM实现CRM扩展权限————————
 3 import re #正则
 4 
 5 #070101_查看自己的客户表_GET
 6 def view_own_Customer(request,*args,**kwargs):
 7     url_path = request.path #获取URL 路径
 8     url_list=re.findall('(\w+)',url_path) #正者表达式 获取参数
 9     url_model_name= url_list[2] #字符串
10     model_name = 'customer'#字符串
11     if url_model_name==model_name: #防止其他表通过权限
12         consultant_id = request.GET.get('consultant') #过滤条件 &consultant=7
13         if consultant_id:
14             consultant_id = int(consultant_id) #转换成 数字
15         if consultant_id == request.user.id: # 账号表 的ID 等于 #当前登陆的ID
16             return True
17         else:
18             return False
19     else:
20         return False
21 
22 #070103_修改自己的客户表_GET
23 #070105_删除自己的客户表_GET
24 def change_own_Customer(request,*args,**kwargs):
25     url_path = request.path #获取URL 路径
26     url_list=re.findall('(\w+)',url_path) #正者表达式 获取参数
27     url_model_name= url_list[2]
28     url_parameter =int(url_list[3])
29     model_name = 'customer'
30     if url_model_name==model_name: #防止其他表通过权限
31         if request.user.id: #如果有ID
32             list= request.user.customer_set.all()#获取ID 的客户表
33             list_id=[]
34             for obtain in list:#循环客户表ID
35                 results=obtain.id
36                 list_id.append(results)#生成列表
37         if url_parameter in list_id: #对比URL参数 在不在 客户表ID里
38             return True
39         else:
40             return False
41     else:
42         return False
43 
44 # ————————75PerfectCRM实现CRM扩展权限————————
# ECJ.py

 

 

 

 

 


 

如果感觉本章博客对您有帮助,请尽情打赏吧!

 

转载于:https://www.cnblogs.com/ujq3/p/9092026.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/71773
推荐阅读
相关标签
  

闽ICP备14008679号