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. # ————————75PerfectCRM实现CRM扩展权限————————
  19. #销售自己的客户库
  20. def sales_customer(request):
  21. user_id=request.user.id #当前登陆的ID
  22. return redirect( '/king_admin/crm/customer/?consultant=%s' %(user_id) ) # 跳转到enrollment_rejection
  23. # ————————75PerfectCRM实现CRM扩展权限————————
  24.  
  25. # 发送邮件的功能 #验证码#密码
  26. class stmp():
  27. def __init__(self):
  28. self.emaillist = [] # 发送给谁
  29. self.code = None # 验证码#密码
  30.  
  31. def stmps(self, request, email, msg_mail): # 传参数#页面,session #邮箱,发送给谁 #内容
  32. self.emaillist.append(email) # 将邮箱地址添加到调用Django发送邮件功能
  33. # ——————生成验证码——————
  34. _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
  35. _upper_cases = _letter_cases.upper() # 大写字母
  36. _numbers = ''.join(map(str, range(3, 10))) # 数字
  37. chars = ''.join((_letter_cases, _upper_cases, _numbers)) # 变成一条字符串
  38. list = random.sample(chars, 4) # 从一条字符串随机选4个字符变成列表
  39. self.code = ''.join(list) # 列表变字符串
  40. # ——————生成验证码——————
  41. # ——————调用Django发送邮件——————
  42. title = 'PerfectCRM项目自动邮件:%s' % self.code # 邮件标题#防止一样的内容被邮箱屏蔽
  43. send_mail(title, # 邮件标题
  44. msg_mail, # 验证码内容
  45. 'perfectcrm@sina.cn', # 发送的邮箱 #根据情况重新配置
  46. self.emaillist, # 接受的邮箱
  47. fail_silently=False, # 静默,抛出异常
  48. )
  49. print('发送邮件成功!没收到要换标题!检查发送邮箱的配置!')
  50. # ——————调用Django发送邮件——————
  51. # ————————47PerfectCRM实现CRM客户报名流程————————
  52. # ————————47PerfectCRM实现CRM客户报名流程————————
  53. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  54. import random # 随机
  55. import string # 字母 数字
  56. from django.core.cache import cache # 缓存
  57. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  58.  
  59. # 报名填写 销售
  60. @login_required # 登陆后页面才能访问
  61. @check_permission #权限控制
  62. def enrollment(request, customer_id):
  63. msgs = {} # 错误信息
  64. customer_obj = models.Customer.objects.get(id=customer_id) # 取到客户信息记录 #返回到页面#报名人
  65. consultant_obj = models.UserProfile.objects.get(id=request.user.id) # 报名课程顾问
  66.  
  67. stmp_mail = {} # 邮件发送成功
  68. stmpemail = stmp() # 实例化发送邮件的功能
  69. email = request.POST.get('email') # 让页面POST提交的值,在页面GET后仍然存在显示
  70. if request.method == "POST":
  71. enroll_form = bpm_forms.EnrollmentForm(request.POST) # 获取数据
  72. if enroll_form.is_valid(): # 表单验证
  73.  
  74. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  75. # msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/"
  76. msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/{random_str}/ "
  77. random_str = ''.join(random.sample(string.ascii_lowercase + string.digits, 8)) # 生成8位随机字符串 #URL使用
  78. url_str = '''customer/registration/{enroll_obj_id}/{random_str}/''' # 报名链接
  79. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  80.  
  81. try:
  82. enroll_form.cleaned_data['customer'] = customer_obj # 添加学员对象 记录 #报名人
  83. enroll_form.cleaned_data['consultant'] = consultant_obj # 报名课程顾问
  84. enroll_obj = models.Enrollment.objects.create(**enroll_form.cleaned_data) # 创建记录
  85.  
  86. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  87. # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#报名记录对应的id,随机字符串,报名链接
  88. sort_url = enroll_obj.id # 获取报名表对应的ID
  89. cache.set(enroll_obj.id, random_str, 61000) # 加入过期时间 #URL使用 # cache缓存
  90. msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名记录对应的id,随机字符串,报名链接
  91. url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名链接
  92. print(url_str)
  93. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  94. except IntegrityError as e:
  95. # 取到这条记录
  96. enroll_obj = models.Enrollment.objects.get(customer_id=customer_obj.id,
  97. enrolled_class_id=enroll_form.cleaned_data[
  98. 'enrolled_class'].id)
  99.  
  100. # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
  101. if enroll_obj.contract_agreed:#学员已经同意合同,提交了身份证
  102. #return redirect('/crm/contract_review/%s/'%enroll_obj.id)#跳转到审核页面
  103. return render(request,'bpm_sales/contract_prompt.html',locals())#跳转提示页面
  104. # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
  105.  
  106. enroll_form.add_error('__all__', '记录已经存在,不能重复创建!')
  107.  
  108. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  109. # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#报名记录对应的id
  110. cache.set(enroll_obj.id, random_str, 61000) # 加入过期时间 #URL使用 # cache缓存
  111. msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名记录对应的id
  112. url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名链接
  113. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  114.  
  115. if email:
  116. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  117. # msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s" %enroll_obj.id
  118. msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s/%s" %(enroll_obj.id,random_str)
  119. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  120. stmpemail.stmps(request, email, msg_mail) # 发送邮件
  121. stmp_mail['ok'] = "邮件已发送成功!"
  122.  
  123. else:
  124. enroll_form = bpm_forms.EnrollmentForm() # modelform表单
  125. return render(request, 'bpm_sales/enrollment.html', locals())
  126. # ————————47PerfectCRM实现CRM客户报名流程————————
  127.  
  128. # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
  129. #学员合同签定
  130.  
  131. # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
  132. import os
  133. from PerfectCRM import settings
  134. import json
  135. # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
  136.  
  137. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  138. from django.shortcuts import HttpResponse #页面返回
  139. # def stu_registration(request,enroll_id):
  140. def stu_registration(request,enroll_id,random_str):
  141. # enroll_obj=models.Enrollment.objects.get(id=enroll_id)#获取报名记录
  142. if cache.get(enroll_id) == random_str: # 判断链接失效了没有
  143. enroll_obj = models.Enrollment.objects.get(id=enroll_id) # 报名记录
  144. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  145.  
  146. # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
  147. enrolled_path='%s/%s/'%(settings.ENROLLED_DATA,enroll_id)#证件上传路径
  148. img_file_len=0 #文件
  149. if os.path.exists(enrolled_path):#判断目录是否存在
  150. img_file_list=os.listdir(enrolled_path)#取目录 下的文件
  151. img_file_len=len(img_file_list)
  152. # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
  153.  
  154. # ————————49PerfectCRM实现CRM客户报名流程学生合同表单验证————————
  155. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  156. if request.method == "POST":
  157.  
  158. # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
  159. ret=False
  160. data=request.POST.get('data')
  161. if data:#如果有删除动作
  162. del_img_path="%s/%s/%s"%(settings.ENROLLED_DATA,enroll_id,data)#路径
  163. print(del_img_path,'=-=-=-=-=-=')
  164. os.remove(del_img_path)
  165. ret=True
  166. return HttpResponse(json.dumps(ret))
  167. if request.is_ajax():#ajax上传图片 #异步提交
  168. print('ajax上传图片 #异步提交中。。。 ',request.FILES)
  169. enroll_data_dir="%s/%s"%(settings.ENROLLED_DATA,enroll_id)#路径 #重要信息不能放在静态文件中
  170. if not os.path.exists(enroll_data_dir):#如果不存目录
  171. os.makedirs(enroll_data_dir,exist_ok=True)#创建目录
  172. for k,file_obj in request.FILES.items(): #循环字典 #上传的文件
  173. with open("%s/%s"%(enroll_data_dir,file_obj.name),'wb') as f: #打开一个文件#路径#获取文件名
  174. for chunk in file_obj.chunks():#循环写入文件 # chunks块
  175. f.write(chunk) #保存文件
  176. return HttpResponse('上传完成!')
  177. # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片————————
  178.  
  179. customer_form = bpm_forms.CustomerForm(request.POST, instance=enroll_obj.customer) # 生成表单验证
  180. if customer_form.is_valid(): # 表单验证通过
  181. customer_form.save() # 保存
  182. enroll_obj.contract_agreed = True # 同意协议
  183. enroll_obj.save() # 保存
  184. status = 1 # 修改报名状态 # 1 已经报名
  185. return render(request, 'bpm_sales/stu_registration.html', locals())
  186.  
  187. else:
  188. if enroll_obj.contract_agreed == True: # 如果协议已经签订
  189. status = 1 # 修改报名状态 # 1 已经报名
  190. else:
  191. status = 0
  192. customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer) # 生成表单
  193. # customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer) # 生成表单
  194. # ————————49PerfectCRM实现CRM客户报名流程学生合同表单验证————————
  195.  
  196. return render(request,'bpm_sales/stu_registration.html',locals())
  197. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  198. # ————————48PerfectCRM实现CRM客户报名流程学生合同————————
  199. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  200. else:
  201. return HttpResponse('链接失效,非法链接,请自重!')
  202. # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码————————
  203.  
  204. # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
  205. from django.shortcuts import redirect
  206. #查询流程提示页面
  207. def contract_prompt(request,enroll_id):
  208. enroll_obj=models.Enrollment.objects.get(id=enroll_id)#取对象
  209. enroll_form= bpm_forms.EnrollmentForm(instance=enroll_obj)#报名表对象
  210. customers_form= bpm_forms.CustomerForm(instance=enroll_obj.customer)#学员的信息
  211. return render(request,'bpm_sales/contract_prompt.html',locals())
  212.  
  213. # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
  214. from bpm.bpm_auxiliary.pagination import Page #分页
  215. # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
  216. # #待审核
  217. @login_required # 登陆后页面才能访问
  218. @check_permission #权限控制
  219. def not_audit(request):
  220. # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
  221. # sign=models.Enrollment.objects.all()#所有的报名表
  222. # print(sign,'sign----->')
  223. sign=models.Enrollment.objects.filter(contract_agreed=True,contract_approved=False).all()#所有的报名表
  224.  
  225. page = Page(request.GET.get('p', 1), len(sign)) #当前页数 默认为1 #总数量
  226. sign = sign[page.start:page.end] # 切片取当前页的数据
  227. page_str = page.page_str('/bpm/not_audit/') #总页数 传入url
  228. # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页————————
  229. return render(request, 'bpm_sales/not_audit.html', locals())#
  230.  
  231. #审核合同
  232. @login_required # 登陆后页面才能访问
  233. @check_permission #权限控制
  234. def contract_review(request,enroll_id):
  235. enroll_obj=models.Enrollment.objects.get(id=enroll_id)#取对象
  236. contract_review = request.user.name #当前登陆人 #合同审核人
  237. #payment_form=forms.PaymentForm()#生成表单
  238. enroll_form= bpm_forms.EnrollmentForm(instance=enroll_obj)#报名表对象
  239. customer_form= bpm_forms.CustomerForm(instance=enroll_obj.customer)#学员的信息
  240. enrolled_path='%s/%s/'%(settings.ENROLLED_DATA,enroll_id)#证件上传路径
  241. if os.path.exists(enrolled_path):#判断目录是否存在
  242. file_list=os.listdir(enrolled_path)#取目录 下的文件
  243. imgs_one=file_list[0] #图片1
  244. imgs_two=file_list[1] #图片2
  245. if request.method=="POST":
  246. enroll_obj.contract_approved = True # 审核通过
  247. enroll_obj.save() #保存
  248. enroll = models.Enrollment.objects.filter(id=enroll_id).update(contract_review=contract_review)#合同审核人
  249. print('审核通过。。。')
  250. return redirect('/bpm/not_audit/')#跳转到待审核
  251. return render(request, 'bpm_sales/contract_review.html', locals())#
  252. #驳回合同
  253. def enrollment_rejection(request,enroll_id):
  254. enroll_obj=models.Enrollment.objects.get(id=enroll_id)#报名表的对象
  255. enroll_obj.contract_agreed=False#修改学员已经同意核同
  256. enroll_obj.save() #保存
  257. return redirect('/bpm/customer/%s/enrollment/'%enroll_obj.customer.id)#跳转到enrollment_rejection
  258. # ————————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. """05客户跟进表"""
  138. class CustomerFollowUp(models.Model):
  139.  
  140. #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  141. customer = models.ForeignKey("Customer", on_delete=models.CASCADE)#客户名 #关联到 客户信息表
  142.  
  143. content = models.TextField(verbose_name="跟进内容")#跟进的内容#TextField无限制长度的文本#verbose_nameAdmin中显示的字段名称
  144.  
  145. #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  146. consultant =models.ForeignKey("UserProfile", on_delete=models.CASCADE) #关联到 账号表
  147.  
  148. intention_choices =( #报名状态
  149. (0,'2周内报名'),
  150. (1,'1个月内报名'),
  151. (2,'近期无报名计划'),
  152. (3,'已在其它机构报名'),
  153. (4,'已报名'),
  154. (5,'已拉黑'),)
  155. #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
  156. intention=models.SmallIntegerField(choices=intention_choices) #报名状态
  157.  
  158. #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
  159. date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
  160.  
  161. def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  162. return "<%s:%s>" %(self.customer.qq,self.intention) #返回#格式化字符串#跨表里的QQ号#报名状态
  163. class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  164. verbose_name_plural = "05客户跟进表"#verbose_name_plural给你的模型类起一个更可读的名字
  165.  
  166. """06学员报名信息表"""
  167. class Enrollment(models.Model):
  168. # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  169. customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字 #关联到 客户信息表
  170. enrolled_class = models.ForeignKey("ClassList",verbose_name="所报班级",on_delete=models.CASCADE)#关联到 班级表
  171. consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问",on_delete=models.CASCADE) #关联到 账号表
  172.  
  173. # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
  174. contract_review = models.CharField(max_length=256, blank=True, null=True, verbose_name="合同审核") # 合同审核
  175. # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
  176.  
  177. #BooleanField布尔值类型#default=False默认(True)不允许出现空字符#verbose_name是Admin中显示的字段名称
  178. contract_agreed = models.BooleanField(default=False,verbose_name="学员已经同意合同")#学员看合同
  179. contract_approved = models.BooleanField(default=False,verbose_name="合同已经审核") #谁审核
  180.  
  181. # ————————53PerfectCRM实现CRM客户报名流程缴费————————
  182. Pay_cost= models.BooleanField(default=False,verbose_name="缴费") #缴费状态#是不是交定金
  183. # ————————53PerfectCRM实现CRM客户报名流程缴费————————
  184.  
  185. # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
  186. date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
  187.  
  188. def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  189. # ————————57PerfectCRM实现admin批量生成上课记录————————
  190. # return "%s %s" %(self.customer,self.enrolled_class)#返回#格式化字符串#学员名字#所报班级
  191. return " 学员:%s |QQ: %s |班级:%s" %(self.customer.name,self.customer,self.enrolled_class)#返回#格式化字符串#学员名字#所报班级
  192. # ————————57PerfectCRM实现admin批量生成上课记录————————
  193. class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  194. unique_together = ("customer","enrolled_class")#联合索引
  195. verbose_name_plural = "06学员报名信息表"#verbose_name_plural给你的模型类起一个更可读的名字
  196.  
  197. """07缴费记录表"""
  198. class Payment(models.Model):
  199. #ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  200. customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字 关联到 客户信息表
  201. course = models.ForeignKey("Course",verbose_name="所报课程",on_delete=models.CASCADE)#关联到 课程表
  202.  
  203. #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称#默认值=500
  204. amount = models.PositiveIntegerField(verbose_name="数额",default=500)#缴费数额
  205.  
  206. #ForeignKey就是表与表之间的某种约定的关系#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  207. consultant = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#缴费给谁 关联到 账号表 #财务人员
  208.  
  209. #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
  210. date=models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
  211.  
  212. def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  213. return "%s %s" %(self.customer,self.amount)#返回#格式化字符串#学员名字#缴费数额
  214. class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  215. verbose_name_plural = "07缴费记录表"#verbose_name_plural给你的模型类起一个更可读的名字
  216.  
  217. """08每节课上课纪录表"""
  218. class CourseRecord(models.Model):
  219. # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  220. from_class = models.ForeignKey("ClassList",verbose_name="班级",on_delete=models.CASCADE) #那个班级
  221.  
  222. #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称
  223. day_num = models.PositiveSmallIntegerField(verbose_name="第几节(天)") #第几节课
  224.  
  225. # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  226. teacher = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#老师是谁 关联到 账号表
  227.  
  228. #BooleanField布尔值类型#default=True默认(True)不允许出现空字符
  229. has_homework = models.BooleanField(default=True) #有没有作业
  230.  
  231. # CharField定长文本#名字最长128#Django可空#数据库可以为空
  232. homework_title = models.CharField(max_length=128,blank=True,null=True) #作业标题
  233.  
  234. #TextField无限制长度的文本#Django可空#数据库可以为空
  235. homework_content = models.TextField(blank=True,null=True) #作业内容
  236.  
  237. #TextField无限制长度的文本#verbose_name是Admin中显示的字段名称
  238. outline =models.TextField(verbose_name="本节课程大纲") #课程主要讲什么
  239.  
  240. # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
  241. date = models.DateField(auto_now_add=True)#创建时间(数据库自增)
  242.  
  243. def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  244. return " %s:%s" %(self.from_class,self.day_num)#返回#格式化字符串#班级#第几节(天)
  245. class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  246. unique_together = ("from_class","day_num") #联合索引
  247. verbose_name_plural = "08每节课上课纪录表" #verbose_name_plural给你的模型类起一个更可读的名字
  248.  
  249. """09学习纪录"""
  250. class StudyRecord(models.Model):
  251. # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  252. student = models.ForeignKey("Enrollment",on_delete=models.CASCADE)#学生名字 关联到 学员报名信息表
  253. course_record = models.ForeignKey("CourseRecord",on_delete=models.CASCADE)#开课记录 # 关联到 每节课上课纪录表
  254.  
  255. attendance_choices = (# 本节课上课状态记录
  256. (0,"已签到"),
  257. (1,"迟到"),
  258. (2,"缺勤"),
  259. (3,"早退"),)
  260. #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
  261. attendance = models.SmallIntegerField(choices=attendance_choices) # 本节课上课状态记录
  262.  
  263. # ————————63PerfectCRM实现CRM讲师下载作业————————
  264. delivery = models.BooleanField(default=False,verbose_name="交作业") #有没有交付作业
  265. # ————————63PerfectCRM实现CRM讲师下载作业————————
  266.  
  267. # ————————61PerfectCRM实现CRM学生上传作业————————
  268. homework_link = models.TextField(blank=True,null=True)#作业链接 #TextField无限制长度的文本#Django可空#数据库可以为空
  269. # ————————61PerfectCRM实现CRM学生上传作业————————
  270.  
  271. score_choices = (#学习成绩
  272. (100,"A+"),
  273. (90,"A"),
  274. (85,"B+"),
  275. (80,"B"),
  276. (75,"B-"),
  277. (70,"C+"),
  278. (65,"C"),
  279. (40,"C-"),
  280. (-20,"D"),
  281. (-50,"COPY"),
  282. (0,"N/A"),)
  283. #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
  284. score = models.SmallIntegerField(choices=score_choices) #学习成绩
  285.  
  286. memo = models.TextField(blank=True,null=True)#TextField无限制长度的文本#Django可空#数据库可以为空
  287.  
  288. # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
  289. date = models.DateField(auto_now_add=True)#创建时间(数据库自增)
  290.  
  291. def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  292. return "%s %s %s" % (self.student, self.course_record, self.score)#返回#格式化字符串#学生名字#开课记录#学习成绩
  293. class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  294. unique_together = ('student','course_record')#联合索引#学生名字#开课记录
  295. verbose_name_plural = "09学习纪录"#verbose_name_plural给你的模型类起一个更可读的名字
  296.  
  297. # ————————34PerfectCRM实现CRM自定义用户————————
  298. # """10账号表"""
  299. # class UserProfile(models.Model):
  300. # from django.contrib.auth.models import User # 使用django内置的用户表
  301. #
  302. # #OneToOneField一对一 #User是django Admin里的账号表#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
  303. # user = models.OneToOneField(User,on_delete=models.CASCADE)# 用户名 #创建外键,关联django用户表
  304. #
  305. # name = models.CharField(max_length=32) #账号名(扩展用户字段)#CharField定长文本
  306. #
  307. # #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。#Django可空
  308. # roles = models.ManyToManyField("Role",blank=True) #角色(权限) # 双向一对多==多对多
  309. #
  310. # def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  311. # return self.name #返回 #账号名
  312. # class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  313. # verbose_name_plural = "10账号表"#verbose_name_plural给你的模型类起一个更可读的名字
  314. # ————————34PerfectCRM实现CRM自定义用户————————
  315.  
  316. # ————————34PerfectCRM实现CRM自定义用户————————
  317. #10账号表,创建用户和超级用户
  318. from django.contrib.auth.models import BaseUserManager
  319. class UserProfileManager(BaseUserManager):
  320. def create_user(self, email, name, password=None):
  321. """
  322.   创建并保存一个用户用给定的邮件,日期
  323.   出生和密码。
  324. """
  325. if not email:#没有email 报错
  326. raise ValueError('用户必须有一个电子邮件地址')
  327.  
  328. user = self.model(
  329. email=self.normalize_email(email),#验证邮箱格式
  330. name=name,
  331. )
  332. user.set_password(password)#加密
  333. user.is_active = True
  334. user.save(using=self._db)
  335. return user
  336. def create_superuser(self, email, name, password):
  337. """
  338.   创建并保存一个超级用户具有给定邮件,日期
  339.   出生和密码。
  340. """
  341. user = self.create_user(email,
  342. password=password,
  343. name=name
  344. )
  345. user.is_active = True
  346. user.is_superuser = True
  347. user.save(using=self._db)
  348. return user
  349.  
  350. """10账号表"""
  351. """
  352.  
  353. #删除数据库
  354.  
  355. #调用objects = UserProfileManager()#创建账号 #关联这个函数
  356.  
  357. #运行 Terminal
  358. # 生成 数据表
  359. # python manage.py makemigrations
  360. # 数据表 迁移
  361. # python manage.py migrate
  362. Django Admin里账号密码重置方法
  363. #运行 Terminal
  364. python manage.py createsuperuser
  365.  
  366. Email address: admin@qq.com
  367. 用户名 : admin
  368. Password: admin123456
  369. Password (again): admin123456
  370. """
  371. from django.contrib.auth.models import AbstractBaseUser
  372. # ————————35PerfectCRM实现CRM重写Admin密码修改————————
  373. from django.utils.translation import ugettext_lazy as _ # 语言国际化
  374. from django.utils.safestring import mark_safe
  375. from django.contrib.auth.models import PermissionsMixin
  376. # class UserProfile(AbstractBaseUser):
  377. class UserProfile(AbstractBaseUser,PermissionsMixin):
  378. # ————————35PerfectCRM实现CRM重写Admin密码修改————————
  379. email=models.EmailField(
  380. verbose_name='邮箱账号',
  381. max_length=255,
  382. unique=True#唯一 #登陆账号
  383. )
  384. name=models.CharField(max_length=32,verbose_name='用户名')
  385.  
  386. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  387. branch = models.ForeignKey( "Branch", verbose_name="所属校区", blank=True, null=True, on_delete=models.CASCADE )
  388. roles = models.ManyToManyField( 'Role', verbose_name="角色", blank=True )
  389. memo = models.TextField( blank=True, null=True, default=None, verbose_name="备注" )
  390. from django.utils import timezone
  391. date_joined = models.DateTimeField( verbose_name="创建时间", default=timezone.now )
  392. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  393.  
  394. # ————————35PerfectCRM实现CRM重写Admin密码修改————————
  395. password = models.CharField(_('password'), max_length=128, help_text=mark_safe('''<a href=\"../password/\">修改密码</a>'''))
  396. # ————————35PerfectCRM实现CRM重写Admin密码修改————————
  397.  
  398. is_active = models.BooleanField(default=True,verbose_name='合法账号')#权限#合法账号
  399. is_superuser = models.BooleanField(default=False,verbose_name='超级账号') #超级账号
  400. objects = UserProfileManager()#创建账号 #关联这个函数
  401. USERNAME_FIELD ='email'#指定做为 #登陆账号
  402. REQUIRED_FIELDS = ['name']#必填字段
  403.  
  404. # ————————60PerfectCRM实现CRM学生上课记录————————
  405. stu_account = models.ForeignKey( "Customer", verbose_name='关联学员帐号', blank=True, null=True, on_delete=models.CASCADE,
  406. help_text='报名成功后创建关联帐户' )
  407. # ————————60PerfectCRM实现CRM学生上课记录————————
  408.  
  409. def get_full_name(self):
  410. return self.email
  411. def get_short_name(self):
  412. #用户确认的电子邮件地址
  413. return self.email
  414. def __str__(self):
  415. return self.name
  416. def has_perm(self,perm,obj=None):
  417. #指明用户是否被认为活跃的。以反选代替删除帐号。
  418. #最简单的可能的答案:是的,总是
  419. return True #有效 账号
  420. def has_module_perms(self, app_label):
  421. #指明用户是否可以登录到这个管理站点。
  422. # 最简单的可能的答案:是的,总是
  423. return True #职员状态
  424. @property
  425. def is_staff(self):
  426. '''“用户的员工吗?”'''
  427. #最简单的可能的答案:所有管理员都是员工
  428. return self.is_superuser#是不是超级用户状态
  429. # AUTH_USER_MODEL = 'crm.UserProfile'#使用自定的admin 表单 #settings.py
  430. # ————————34PerfectCRM实现CRM自定义用户————————
  431. # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
  432. class Meta:
  433. verbose_name_plural = '10CRM账户表'
  434. permissions = (
  435. ('crm_010101_all_table_data_list_GET', '010101_全部查看数据_GET'),
  436. ('crm_010102_all_table_data_list_POST', '010102_全部查看数据_POST'),
  437. ('crm_010103_all_table_add_GET', '010103_全部添加数据_GET'),
  438. ('crm_010104_all_table_add_POST', '010104_全部添加数据_POST'),
  439. ('crm_010105_all_table_change_GET', '010105_全部修改数据_GET'),
  440. ('crm_010106_all_table_change_POST', '010106_全部修改数据_POST'),
  441. ('crm_010107_all_table_delete_GET', '010107_全部删除数据_GET'),
  442. ('crm_010108_all_table_delete_POST', '010108_全部删除数据_POST'),
  443. ('crm_010109_all_password_reset_GET', '010109_全部密码重置_GET'),
  444. ('crm_010110_all_password_reset_POST', '010110_全部密码重置_POST'),
  445.  
  446. ('crm_010201_only_view_Branch_GET', '010201_只能查看校区表_GET'),
  447. ('crm_010202_only_view_Branch_POST', '010202_只能查看校区表_POST'),
  448. ('crm_010203_only_add_Branch_GET', '010203_只能添加校区表_GET'),
  449. ('crm_010204_only_add_Branch_POST', '010204_只能添加校区表_POST'),
  450. ('crm_010205_only_change_Branch_GET', '010205_只能修改校区表_GET'),
  451. ('crm_010206_only_change_Branch_POST', '010206_只能修改校区表_POST'),
  452. ('crm_010207_only_delete_Branch_GET', '010207_只能删除校区表_GET'),
  453. ('crm_010208_only_delete_Branch_POST', '010208_只能删除校区表_POST'),
  454.  
  455. ('crm_010301_only_view_ClassList_GET', '010301_只能查看班级表_GET'),
  456. ('crm_010302_only_view_ClassList_POST', '010302_只能查看班级表_POST'),
  457. ('crm_010303_only_add_ClassList_GET', '010303_只能添加班级表_GET'),
  458. ('crm_010304_only_add_ClassList_POST', '010304_只能添加班级表_POST'),
  459. ('crm_010305_only_change_ClassList_GET', '010305_只能修改班级表_GET'),
  460. ('crm_010306_only_change_ClassList_POST', '010306_只能修改班级表_POST'),
  461. ('crm_010307_only_delete_ClassList_GET', '010307_只能删除班级表_GET'),
  462. ('crm_010308_only_delete_ClassList_POST', '010308_只能删除班级表_POST'),
  463.  
  464. ('crm_010401_only_view_Course_GET', '010401_只能查看课程表_GET'),
  465. ('crm_010402_only_view_Course_POST', '010402_只能查看课程表_POST'),
  466. ('crm_010403_only_add_Course_GET', '010403_只能添加课程表_GET'),
  467. ('crm_010404_only_add_Course_POST', '010404_只能添加课程表_POST'),
  468. ('crm_010405_only_change_Course_GET', '010405_只能修改课程表_GET'),
  469. ('crm_010406_only_change_Course_POST', '010406_只能修改课程表_POST'),
  470. ('crm_010407_only_delete_Course_GET', '010407_只能删除课程表_GET'),
  471. ('crm_010408_only_delete_Course_POST', '010408_只能删除课程表_POST'),
  472.  
  473. ('crm_010501_only_view_Customer_GET', '010501_只能查看客户表_GET'),
  474. ('crm_010502_only_view_Customer_POST', '010502_只能查看客户表_POST'),
  475. ('crm_010503_only_add_Customer_GET', '010503_只能添加客户表_GET'),
  476. ('crm_010504_only_add_Customer_POST', '010504_只能添加客户表_POST'),
  477. ('crm_010505_only_change_Customer_GET', '010505_只能修改客户表_GET'),
  478. ('crm_010506_only_change_Customer_POST', '010506_只能修改客户表_POST'),
  479. ('crm_010507_only_delete_Customer_GET', '010507_只能删除客户表_GET'),
  480. ('crm_010508_only_delete_Customer_POST', '010508_只能删除客户表_POST'),
  481.  
  482. ('crm_010601_only_view_CustomerFollowUp_GET', '010601_只能查看跟进表_GET'),
  483. ('crm_010602_only_view_CustomerFollowUp_POST', '010602_只能查看跟进表_POST'),
  484. ('crm_010603_only_add_CustomerFollowUp_GET', '010603_只能添加跟进表_GET'),
  485. ('crm_010604_only_add_CustomerFollowUp_POST', '010604_只能添加跟进表_POST'),
  486. ('crm_010605_only_change_CustomerFollowUp_GET', '010605_只能修改跟进表_GET'),
  487. ('crm_010606_only_change_CustomerFollowUp_POST', '010606_只能修改跟进表_POST'),
  488. ('crm_010607_only_delete_CustomerFollowUp_GET', '010607_只能删除跟进表_GET'),
  489. ('crm_010608_only_delete_CustomerFollowUp_POST', '010608_只能删除跟进表_POST'),
  490.  
  491. ('crm_010701_only_view_Enrollment_GET', '010701_只能查看报名表_GET'),
  492. ('crm_010702_only_view_Enrollment_POST', '010702_只能查看报名表_POST'),
  493. ('crm_010703_only_add_Enrollment_GET', '010703_只能添加报名表_GET'),
  494. ('crm_010704_only_add_Enrollment_POST', '010704_只能添加报名表_POST'),
  495. ('crm_010705_only_change_Enrollment_GET', '010705_只能修改报名表_GET'),
  496. ('crm_010706_only_change_Enrollment_POST', '010706_只能修改报名表_POST'),
  497. ('crm_010707_only_delete_Enrollment_GET', '010707_只能删除报名表_GET'),
  498. ('crm_010708_only_delete_Enrollment_POST', '010708_只能删除报名表_POST'),
  499.  
  500. ('crm_010801_only_view_Payment_GET', '010801_只能查看缴费表_GET'),
  501. ('crm_010802_only_view_Payment_POST', '010802_只能查看缴费表_POST'),
  502. ('crm_010803_only_add_Payment_GET', '010803_只能添加缴费表_GET'),
  503. ('crm_010804_only_add_Payment_POST', '010804_只能添加缴费表_POST'),
  504. ('crm_010805_only_change_Payment_GET', '010805_只能修改缴费表_GET'),
  505. ('crm_010806_only_change_Payment_POST', '010806_只能修改缴费表_POST'),
  506. ('crm_010807_only_delete_Payment_GET', '010807_只能删除缴费表_GET'),
  507. ('crm_010808_only_delete_Payment_POST', '010808_只能删除缴费表_POST'),
  508.  
  509. ('crm_010901_only_view_CourseRecord_GET', '010901_只能查看上课表_GET'),
  510. ('crm_010902_only_view_CourseRecord_POST', '010902_只能查看上课表_POST'),
  511. ('crm_010903_only_add_CourseRecord_GET', '010903_只能添加上课表_GET'),
  512. ('crm_010904_only_add_CourseRecord_POST', '010904_只能添加上课表_POST'),
  513. ('crm_010905_only_change_CourseRecord_GET', '010905_只能修改上课表_GET'),
  514. ('crm_010906_only_change_CourseRecord_POST', '010906_只能修改上课表_POST'),
  515. ('crm_010907_only_delete_CourseRecord_GET', '010907_只能删除上课表_GET'),
  516. ('crm_010908_only_delete_CourseRecord_POST', '010908_只能删除上课表_POST'),
  517.  
  518. ('crm_011001_only_view_StudyRecord_GET', '011001_只能查看学习表_GET'),
  519. ('crm_011002_only_view_StudyRecord_POST', '011002_只能查看学习表_POST'),
  520. ('crm_011003_only_add_StudyRecord_GET', '011003_只能添加学习表_GET'),
  521. ('crm_011004_only_add_StudyRecord_POST', '011004_只能添加学习表_POST'),
  522. ('crm_011005_only_change_StudyRecord_GET', '011005_只能修改学习表_GET'),
  523. ('crm_011006_only_change_StudyRecord_POST', '011006_只能修改学习表_POST'),
  524. ('crm_011007_only_delete_StudyRecord_GET', '011007_只能删除学习表_GET'),
  525. ('crm_011008_only_delete_StudyRecord_POST', '011008_只能删除学习表_POST'),
  526.  
  527. ('crm_011101_only_view_UserProfile_GET', '011101_只能查看账号表_GET'),
  528. ('crm_011102_only_view_UserProfile_POST', '011102_只能查看账号表_POST'),
  529. ('crm_011103_only_add_UserProfile_GET', '011103_只能添加账号表_GET'),
  530. ('crm_011104_only_add_UserProfile_POST', '011104_只能添加账号表_POST'),
  531. ('crm_011105_only_change_UserProfile_GET', '011105_只能修改账号表_GET'),
  532. ('crm_011106_only_change_UserProfile_POST', '011106_只能修改账号表_POST'),
  533. ('crm_011107_only_delete_UserProfile_GET', '011107_只能删除账号表_GET'),
  534. ('crm_011108_only_delete_UserProfile_POST', '011108_只能删除账号表_POST'),
  535.  
  536. ('crm_011201_only_view_Role_GET', '011201_只能查看角色表_GET'),
  537. ('crm_011202_only_view_Role_POST', '011202_只能查看角色表_POST'),
  538. ('crm_011203_only_add_Role_GET', '011203_只能添加角色表_GET'),
  539. ('crm_011204_only_add_Role_POST', '011204_只能添加角色表_POST'),
  540. ('crm_011205_only_change_Role_GET', '011205_只能修改角色表_GET'),
  541. ('crm_011206_only_change_Role_POST', '011206_只能修改角色表_POST'),
  542. ('crm_011207_only_delete_Role_GET', '011207_只能删除角色表_GET'),
  543. ('crm_011208_only_delete_Role_POST', '011208_只能删除角色表_POST'),
  544.  
  545. ('crm_011301_only_view_Tag_GET', '011301_只能查看标签表_GET'),
  546. ('crm_011302_only_view_Tag_POST', '011302_只能查看标签表_POST'),
  547. ('crm_011303_only_add_Tag_GET', '011303_只能添加标签表_GET'),
  548. ('crm_011304_only_add_Tag_POST', '011304_只能添加标签表_POST'),
  549. ('crm_011305_only_change_Tag_GET', '011305_只能修改标签表_GET'),
  550. ('crm_011306_only_change_Tag_POST', '011306_只能修改标签表_POST'),
  551. ('crm_011307_only_delete_Tag_GET', '011307_只能删除标签表_GET'),
  552. ('crm_011308_only_delete_Tag_POST', '011308_只能删除标签表_POST'),
  553.  
  554. ('crm_011401_only_view_FirstLayerMenu_GET', '011401_只能查看一层菜单_GET'),
  555. ('crm_011402_only_view_FirstLayerMenu_POST', '011402_只能查看一层菜单_POST'),
  556. ('crm_011403_only_add_FirstLayerMenu_GET', '011403_只能添加一层菜单_GET'),
  557. ('crm_011404_only_add_FirstLayerMenu_POST', '011404_只能添加一层菜单_POST'),
  558. ('crm_011405_only_change_FirstLayerMenu_GET', '011405_只能修改一层菜单_GET'),
  559. ('crm_011406_only_change_FirstLayerMenu_POST', '011406_只能修改一层菜单_POST'),
  560. ('crm_011407_only_delete_FirstLayerMenu_GET', '011407_只能删除一层菜单_GET'),
  561. ('crm_011408_only_delete_FirstLayerMenu_POST', '011408_只能删除一层菜单_POST'),
  562.  
  563. ('crm_011501_only_view_SubMenu_GET', '011501_只能查看二层菜单_GET'),
  564. ('crm_011502_only_view_SubMenu_POST', '011502_只能查看二层菜单_POST'),
  565. ('crm_011503_only_add_SubMenu_GET', '011503_只能添加二层菜单_GET'),
  566. ('crm_011504_only_add_SubMenu_POST', '011504_只能添加二层菜单_POST'),
  567. ('crm_011505_only_change_SubMenu_GET', '011505_只能修改二层菜单_GET'),
  568. ('crm_011506_only_change_SubMenu_POST', '011506_只能修改二层菜单_POST'),
  569. ('crm_011507_only_delete_SubMenu_GET', '011507_只能删除二层菜单_GET'),
  570. ('crm_011508_only_delete_SubMenu_POST', '011508_只能删除二层菜单_POST'),
  571.  
  572. ('crm_011601_only_view_Groups_GET', '011601_只能查看权限组_GET'),
  573. ('crm_011602_only_view_Groups_POST', '011602_只能查看权限组_POST'),
  574. ('crm_011603_only_add_Groups_GET', '011603_只能添加权限组_GET'),
  575. ('crm_011604_only_add_Groups_POST', '011604_只能添加权限组_POST'),
  576. ('crm_011605_only_change_Groups_GET', '011605_只能修改权限组_GET'),
  577. ('crm_011606_only_change_Groups_POST', '011606_只能修改权限组_POST'),
  578. ('crm_011607_only_delete_Groups_GET', '011607_只能删除权限组_GET'),
  579. ('crm_011608_only_delete_Groups_POST', '011608_只能删除权限组_POST'),
  580.  
  581. ('crm_011701_own_password_reset_GET', '011701_自己密码重置_GET'),
  582. ('crm_011702_own_password_reset_POST', '011702_自己密码重置_POST'),
  583.  
  584. ('crm_020101_all_not_audit_GET', '020101_销售查看全部的客户未审核_GET'),
  585. ('crm_020103_all_enrollment_GET', '020103_销售给全部的客户报名课程_GET'),
  586. ('crm_020104_all_enrollment_POST', '020104_销售给全部的客户报名课程_POST'),
  587. ('crm_020105_all_contract_review_GET', '020105_销售给全部的客户审核合同_GET'),
  588. ('crm_020116_all_contract_review_POST', '020116_销售给全部的客户审核合同_POST'),
  589.  
  590. ('crm_020201_own_enrollment_GET', '020201_销售给自己的客户报名课程_GET'),
  591. ('crm_020202_own_enrollment_POST', '020202_销售给自己的客户报名课程_POST'),
  592. ('crm_020203_own_contract_review_GET', '020203_销售给自己的客户审核合同_GET'),
  593. ('crm_020204_own_contract_review_POST', '020204_销售给自己的客户审核合同_POST'),
  594.  
  595. ('crm_030101_all_not_payment_GET', '030101_财务查看全部的客户未缴费_GET'),
  596. ('crm_030102_all_not_payment_POST', '030102_财务查看全部的客户未缴费_POST'),
  597. ('crm_030103_all_already_payment_GET', '030103_财务查看全部的客户已缴费_GET'),
  598. ('crm_030104_all_already_payment_POST', '030104_财务查看全部的客户已缴费_POST'),
  599. ('crm_030105_all_payment_GET', '030105_财务进行全部的客户缴费_GET'),
  600. ('crm_030106_all_payment_POST', '030106_财务进行全部的客户缴费_POST'),
  601.  
  602. ('crm_040101_own_student_course_GET', '040101_学生查看自己的课程_GET'),
  603. ('crm_040102_own_student_course_POST', '040102_学生查看自己的课程_POST'),
  604. ('crm_040103_own_studyrecords_GET', '040103_学生自己的上课记录_GET'),
  605. ('crm_040104_own_studyrecords_POST', '040104_学生自己的上课记录_POST'),
  606. ('crm_040105_own_homework_detail_GET', '040105_学生自己的作业详情_GET'),
  607. ('crm_040106_own_homework_detail_POST', '040106_学生自己的作业详情_POST'),
  608.  
  609. ('crm_050101_own_teacher_class_GET', '050101_讲师查看自己的班级_GET'),
  610. ('crm_050102_own_teacher_class_POST', '050102_讲师查看自己的班级_POST'),
  611. ('crm_050103_own_teacher_class_detail_GET', '050103_讲师查看自己的课节详情_GET'),
  612. ('crm_050104_own_teacher_class_detail_POST', '050104_讲师查看自己的课节详情_POST'),
  613. ('crm_050105_own_teacher_lesson_detail_GET', '050105_讲师查看自己的课节学员_GET'),
  614. ('crm_050106_own_teacher_lesson_detail_POST', '050106_讲师查看自己的课节学员_POST'),
  615. ('crm_050107_own_howk_down_GET', '050107_讲师自己的学员作业下载_GET'),
  616. ('crm_050108_own_howk_down_POST', '050108_讲师自己的学员作业下载_POST'),
  617.  
  618. ('crm_060101_own_coursetop_details_GET', '060101_讲师查看自己的班级排名详情_GET'),
  619. ('crm_060102_own_coursetop_details_POST', '060102_讲师查看自己的班级排名详情_POST'),
  620. ('crm_060103_own_coursetop_score_GET', '060103_讲师查看自己的班级分数排行_GET'),
  621. ('crm_060104_own_coursetop_score_POST', '060104_讲师查看自己的班级排分数排行_POST'),
  622. ('crm_060105_own_coursetop_homework_GET', '060105_讲师查看自己的班级作业排行_GET'),
  623. ('crm_060106_own_coursetop_homework_POST', '060106_讲师查看自己的班级作业排行_POST'),
  624. ('crm_060107_own_coursetop_attendance_GET', '060107_讲师查看自己的班级出勤排行_GET'),
  625. ('crm_060108_own_coursetop_attendance_POST', '060108_讲师查看自己的班级出勤排行_POST'),
  626.  
  627. )
  628. # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
  629. # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
  630. """15权限组"""
  631. from django.contrib.auth.models import Group
  632. class Groups(Group):
  633. class Meta:
  634. verbose_name_plural = '15权限组'
  635. # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
  636. # ————————75PerfectCRM实现CRM扩展权限————————
  637. from django.contrib.auth.models import Permission
  638. class Permissions(Permission):
  639. dic_name = models.CharField(_('dic_name'), max_length=255)
  640. class Meta:
  641. verbose_name_plural = "16扩展权限"
  642. # ————————75PerfectCRM实现CRM扩展权限————————
  643.  
  644. """11角色表"""
  645. class Role(models.Model):
  646. name = models.CharField(unique=True,max_length=32)#角色名#CharField定长文本#角色名不可以重复#最长度=32字节
  647.  
  648. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  649. menus = models.ManyToManyField('FirstLayerMenu',verbose_name='一层菜单',blank=True)
  650. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  651.  
  652. def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  653. return self.name#返回 #角色名
  654. class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  655. verbose_name_plural = "11角色表" #verbose_name_plural给你的模型类起一个更可读的名字
  656.  
  657. """12标签表"""
  658. class Tag(models.Model):
  659. name = models.CharField(max_length=64,unique=True) #标签名#CharField定长文本#最长度=64字节#不可以重复
  660. def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
  661. return self.name #返回 #标签名
  662. class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
  663. verbose_name_plural = "12标签表" #verbose_name_plural给你的模型类起一个更可读的名字
  664.  
  665. # ————————01PerfectCRM基本配置ADMIN————————
  666.  
  667. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  668. """13一层菜单名"""
  669. class FirstLayerMenu(models.Model):
  670. '''第一层侧边栏菜单'''
  671. name = models.CharField('一层菜单名',max_length=64)
  672. url_type_choices = ((0,'相关的名字'),(1,'固定的URL'))
  673. url_type = models.SmallIntegerField(choices=url_type_choices,default=0)
  674. url_name = models.CharField(max_length=64,verbose_name='一层菜单路径')
  675. order = models.SmallIntegerField(default=0,verbose_name='菜单排序')
  676. sub_menus = models.ManyToManyField('SubMenu',blank=True)
  677.  
  678. def __str__(self):
  679. return self.name
  680.  
  681. class Meta:
  682. verbose_name_plural = "13第一层菜单"
  683.  
  684. """14二层菜单名"""
  685. class SubMenu(models.Model):
  686. '''第二层侧边栏菜单'''
  687. name = models.CharField('二层菜单名', max_length=64)
  688. url_type_choices = ((0,'相关的名字'),(1,'固定的URL'))
  689. url_type = models.SmallIntegerField(choices=url_type_choices,default=0)
  690. url_name = models.CharField(max_length=64, verbose_name='二层菜单路径')
  691. order = models.SmallIntegerField(default=0, verbose_name='菜单排序')
  692.  
  693. def __str__(self):
  694. return self.name
  695.  
  696. class Meta:
  697. verbose_name_plural = "14第二层菜单"
  698. # ————————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. # ————————62PerfectCRM实现CRM讲师讲课记录————————
  21. # 02班级表
  22. class ClassListAdmin(BaseAdmin):
  23. list_display = ['id', 'branch', 'course', 'class_type', 'semester', 'start_date', 'end_date'] # 显示字段表头
  24. list_filter = ['branch', 'course', 'class_type'] # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
  25. filter_horizontal = ['teachers'] #复选框
  26. site.register(models.ClassList,ClassListAdmin) #02班级表
  27.  
  28. # ————————62PerfectCRM实现CRM讲师讲课记录————————
  29.  
  30. #04客户信息表
  31. class CustomerAdmin(BaseAdmin):#定制Djanago admin
  32. # ————————54PerfectCRM实现CRM客户报名链接————————
  33. # list_display = ('id', 'qq', 'source', 'consultant', 'content', 'date') # 显示字段表头
  34. list_display = ('id', 'qq', 'source', 'consultant', 'content', 'date','status','enroll') # 显示字段表头
  35. # ————————54PerfectCRM实现CRM客户报名链接————————
  36. # ————————11PerfectCRM实现King_admin分页显示条数————————
  37. list_per_page = 2 #分页条数 # 默认分页条数10
  38. # ————————11PerfectCRM实现King_admin分页显示条数————————
  39. # ————————16PerfectCRM实现King_admin日期过滤————————
  40. # ————————15PerfectCRM实现King_admin多条件过滤————————
  41. # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
  42. # list_filter = ('source','consultant','consult_courses',)
  43. list_filter = ('date','source','consultant','consult_courses',)
  44. # ————————15PerfectCRM实现King_admin多条件过滤————————
  45. # ————————16PerfectCRM实现King_admin日期过滤————————
  46. # ————————18PerfectCRM实现King_admin搜索关键字————————
  47. #搜索(不能包含CharField)(注意加 逗号 , )
  48. search_fields = ('name','qq',)
  49. # ————————18PerfectCRM实现King_admin搜索关键字————————
  50. # ————————26PerfectCRM实现King_admin自定义排序————————
  51. ordering = '-qq' #自定义排序,默认'-id'
  52. # ————————26PerfectCRM实现King_admin自定义排序————————
  53. # ————————27PerfectCRM实现King_admin编辑复选框————————
  54. filter_horizontal = ('tags',) #复选框
  55. # ————————27PerfectCRM实现King_admin编辑复选框————————
  56. # ————————33PerfectCRM实现King_admin编辑整张表限制————————
  57. readonly_table=True#默认表单不锁定
  58. # ————————33PerfectCRM实现King_admin编辑整张表限制————————
  59.  
  60. # ————————55PerfectCRM实现CRM客户报名状态颜色变化————————
  61. colored_fields = {
  62. 'status':{'已报名':"rgba(145, 255, 0, 0.78)",
  63. '未报名':"#ddd"},}
  64. # ————————55PerfectCRM实现CRM客户报名状态颜色变化————————
  65.  
  66. # ————————54PerfectCRM实现CRM客户报名链接————————
  67. def enroll(self):
  68. '''报名'''
  69. print("customize field enroll",self)
  70. link_name = "报名"
  71. if self.instance.status == 0:
  72. link_name = "报名新课程"
  73. return '''<a target="_blank" class="btn-link" href="/bpm/customer/%s/enrollment/">点击%s</a> ''' % (self.instance.id,link_name)
  74. # url(r'^customer/(\d+)/enrollment/$', sales_views.enrollment, name="enrollment"), # 客户招生#报名流程一 下一步
  75. # target属性用于表示所链接文件打开到的位置 #记住,“”内的文字只是表示一个对象的名子。
  76. enroll.display_name = "报名链接"
  77. # ————————54PerfectCRM实现CRM客户报名链接————————
  78.  
  79. # ————————24PerfectCRM实现King_admin自定义操作数据————————
  80. # from django.shortcuts import render
  81. actions = ['test_actions',]#定制功能 #测试返回到一个新页面
  82. def test_actions(self,request,arg2):#对应的函数 #request类自己的请求 #arg2类的内容
  83. return render(request,"king_admin/table_index.html")
  84. test_actions.short_description = "测试显示中文"
  85. # ————————24PerfectCRM实现King_admin自定义操作数据————————
  86.  
  87. # ————————28PerfectCRM实现King_admin编辑限制————————
  88. # ————————31PerfectCRM实现King_admin编辑多对多限制————————
  89. # readonly_fields = ('qq', 'consultant',) # 不可修改
  90. readonly_fields = ('qq', 'consultant','tags',) # 不可修改
  91. # ————————31PerfectCRM实现King_admin编辑多对多限制————————
  92.  
  93. # ————————29PerfectCRM实现King_admin编辑自定义限制————————
  94. def default_form_validation(self,obj):
  95. print('validation:制定的',obj.cleaned_data)
  96. consult_course=obj.cleaned_data.get('content','')#自制验证字段
  97. if len(consult_course)<10:
  98. return ValidationError(#添加错误信息 返回
  99. ("该字段%(field)s 咨询内容记录不能少于10个字符"),
  100. code='invalid',
  101. params={'field':'content',},
  102. )
  103. # ————————29PerfectCRM实现King_admin编辑自定义限制————————
  104.  
  105. # ————————28PerfectCRM实现King_admin编辑限制————————
  106.  
  107. # ————————30PerfectCRM实现King_admin编辑自定义字段验证————————
  108. def clean_name(self,obj,*args,**kwargs):#名称验证 单个
  109. name=obj.cleaned_data['name']
  110. if not name:
  111. obj.add_error('name','不能为空!')
  112. return ValidationError(#添加错误信息 返回
  113. ("%(field)s:该字段 不能为空"),
  114. code='invalid',
  115. params={'field':'name',},
  116. )
  117. elif len(name)<5:
  118. obj.add_error('name','不能小于5个字符!')
  119. #return ValidationError('',)
  120. return ValidationError(#添加错误信息 返回
  121. ("%(field)s:该字段 不能小于5个字符!"),
  122. code='invalid',
  123. params={'field':'name',},
  124. )
  125. # ————————30PerfectCRM实现King_admin编辑自定义字段验证————————
  126.  
  127. # ————————34PerfectCRM实现CRM自定义用户————————
  128. #10账号表
  129. class UserProfileAdmin(BaseAdmin):#定制Djanago admin
  130. list_display = ('id', 'email', 'name') # 显示字段表头
  131.  
  132. # ————————36PerfectCRM实现King_admin密码修改————————
  133. readonly_fields = ('password',) # 不可修改,限制
  134.  
  135. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  136. # filter_horizontal = ('user_permissions','groups') #复选框
  137. filter_horizontal = ('user_permissions', 'groups','roles') # 复选框
  138. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  139.  
  140. modelform_exclude_fields=['last_login']#排除#不显示 #自增日期 #base_admin.py #forms.py
  141. # ————————36PerfectCRM实现King_admin密码修改————————
  142.  
  143. site.register(models.UserProfile, UserProfileAdmin)
  144. # ————————34PerfectCRM实现CRM自定义用户————————
  145.  
  146. # ————————05PerfectCRM实现King_admin注册功能获取内存————————
  147. # register(models.Customer,CustomerAdmin)
  148. # register(models.CourseRecord)
  149. site.register(models.Customer,CustomerAdmin)
  150. # ————————58PerfectCRM实现king_admin批量生成上课记录————————
  151. # site.register(models.CourseRecord)
  152. # ————————58PerfectCRM实现king_admin批量生成上课记录————————
  153. # ————————05PerfectCRM实现King_admin注册功能获取内存————————
  154.  
  155. # ————————04PerfectCRM实现King_admin注册功能————————
  156.  
  157. # ————————56PerfectCRM实现CRM客户报名缴费链接————————
  158. # 06学员报名信息表
  159. class EnrollmentAdmin(BaseAdmin): # 定制Djanago admin
  160. list_display = ('id', 'customer', 'enrolled_class', 'consultant', 'Pay_cost', 'date', 'payment') # 显示字段表头
  161.  
  162. # ————————58PerfectCRM实现king_admin批量生成上课记录————————
  163. list_filter = ('enrolled_class','consultant', 'Pay_cost',) # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
  164. # ————————58PerfectCRM实现king_admin批量生成上课记录————————
  165.  
  166. colored_fields = {
  167. 'Pay_cost': {True: "rgba(145, 255, 0, 0.78)",
  168. False: "#ddd"}, }
  169. def payment(self):
  170. link_name = "增加缴费"
  171. if self.instance.Pay_cost == False:
  172. link_name = "缴费"
  173. return '''<a target="_blank" class="btn-link" href="/bpm/payment/%s/" >点击%s</a> ''' % (self.instance.id, link_name)
  174. # url(r'^payment/(\d+)/$', financial_views.payment, name="payment"), # 报名流程四 缴费 #财务
  175. # target属性用于表示所链接文件打开到的位置 #记住,“”内的文字只是表示一个对象的名子。
  176. payment.display_name = "缴费链接"
  177. site.register(models.Enrollment, EnrollmentAdmin) # 06学员报名信息表
  178. # ————————56PerfectCRM实现CRM客户报名缴费链接————————
  179.  
  180. # ————————58PerfectCRM实现king_admin批量生成上课记录————————
  181. # 07缴费记录表
  182. class PaymentAdmin(BaseAdmin):
  183. list_display = ['id', 'customer', 'course', 'amount', 'consultant','date'] # 显示字段表头
  184. list_filter = ('customer', 'course', 'consultant',) # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
  185.  
  186. from django.shortcuts import render, HttpResponse, redirect
  187. # 08每节课上课纪录表
  188. class CourseRecordAdmin(BaseAdmin):
  189. list_display = ['id', 'from_class', 'day_num', 'teacher', 'has_homework', 'homework_title', 'homework_content','outline', 'date'] # 显示字段表头
  190. list_filter = ('from_class', 'teacher', 'date') # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
  191. def initialize_studyrecords(self, request, queryset): # 制定功能
  192. print('initialize_studyrecords', self, request, queryset)
  193. if len(queryset) > 1:
  194. return HttpResponse("同时只能选择一个班级!")
  195. print('获取对应的学员', queryset[0].from_class.enrollment_set.all()) # _set反向查询
  196. new_obj_list = [] # 用于批量创建事务 #防止数据库事物回滚
  197. for enrll_obj in queryset[0].from_class.enrollment_set.all(): # 创建学习记录
  198. # models.StudyRecord.objects.get_or_create( #get_or_ #防止报错
  199. # student=enrll_obj,#对应学员
  200. # course_record=queryset[0],
  201. # attendance=0,#签到状态,默认签到,
  202. # score=0,#成绩
  203. # )
  204.  
  205. # 防止数据库事物回滚 #"""09学习纪录"""
  206. new_obj_list.append(models.StudyRecord(
  207. student=enrll_obj, # 对应学员
  208. course_record=queryset[0], # 班级#节课
  209. attendance=0, # 签到状态,默认签到,
  210. score=0, # 成绩
  211. ))
  212. try:
  213. models.StudyRecord.objects.bulk_create(new_obj_list) # bulk_create批量创建数据库事物 #统一最后保存
  214. except Exception as e:
  215. return HttpResponse('批量创建失败,本节课可能有相应的上课记录')
  216.  
  217. return redirect("/king_admin/crm/studyrecord/?course_record=%s" % queryset[0].id) # 学习记录 #加上过滤
  218.  
  219. actions = ['initialize_studyrecords', ]
  220. initialize_studyrecords.short_description = "创建班级本节上课记录" # 显示别名
  221. # 09学习纪录
  222. class StudyRecordAdmin(BaseAdmin):
  223. list_display = ['id', 'student', 'course_record', 'attendance', 'score', 'date'] # 显示字段表头
  224.  
  225. list_filter = ['course_record', 'attendance', 'score', 'student'] # 过滤器(可以包含ManyToManyField) (注意加 逗号 , )
  226.  
  227. list_editable = ['score', 'attendance'] # 可编辑 #用于上课点名 批改成绩
  228.  
  229. site.register(models.Payment, PaymentAdmin) # 07缴费记录表
  230. site.register(models.CourseRecord, CourseRecordAdmin) # 08每节课上课纪录表
  231. site.register(models.StudyRecord, StudyRecordAdmin) # 09学习纪录
  232. # ————————58PerfectCRM实现king_admin批量生成上课记录————————
  233.  
  234. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  235. # 11角色表
  236. class RoleAdmin(BaseAdmin):
  237. list_display = ['id', 'name'] # 显示字段表头
  238. filter_horizontal = ['menus'] # 复选框
  239. site.register(models.Role,RoleAdmin) #11角色表
  240.  
  241. # 13一层菜单名
  242. class FirstLayerMenuAdmin(BaseAdmin):
  243. list_display = ['id', 'name', 'url_type', 'url_name', 'order'] # 显示字段表头
  244. site.register(models.FirstLayerMenu,FirstLayerMenuAdmin) #13一层菜单名
  245. # 14二层菜单名
  246. class SubMenuMenuAdmin(BaseAdmin):
  247. list_display = ['id', 'name', 'url_type', 'url_name', 'order'] # 显示字段表头
  248. site.register(models.SubMenu,SubMenuMenuAdmin) #14二层菜单名
  249. # ————————72PerfectCRM实现CRM动态菜单和角色————————
  250.  
  251. # ————————74PerfectCRM实现CRM权限和权限组限制访问URL————————
  252. class GroupsAdmin(BaseAdmin):
  253. list_display = ['id', 'name'] # 显示字段表头
  254. filter_horizontal = ['permissions'] # 复选框
  255. site.register(models.Groups,GroupsAdmin) #14二层菜单名
  256. # ————————74PerfectCRM实现CRM权限和权限组限制访问URL————————
  257.  
  258. # ————————75PerfectCRM实现CRM扩展权限————————
  259. class PermissionsAdmin(BaseAdmin):
  260. list_display = ['id', 'name','codename','dic_name'] # 显示字段表头
  261. site.register(models.Permissions,PermissionsAdmin) #16扩展权限
  262. # ————————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 当前urlurl_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. if per_url_name == current_url_name: #权限字典的 URL ==当前请求的url #crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
  66. if per_method == request.method: #权限字典的 请求方法 == 当前请求的方法 #crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
  67. #逐个匹配参数,看每个参数时候都能对应的上。
  68. args_matched = False #参数匹配 #仅供参数
  69. for item in perm_args: #循环列表参数 #crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
  70. request_method_func = getattr(request,per_method) #反射 #请求方法 #GET #POST
  71. if request_method_func.get(item,None):# 如果request字典中有此参数
  72. args_matched = True
  73. else:
  74. print("参数不匹配......")
  75. args_matched = False
  76. break # 有一个参数不能匹配成功,则判定为假,退出该循环。
  77. else:
  78. args_matched = True #没有执行 break 表示 列表匹配成功 #防止列表没有使用参数时出错
  79.  
  80. #匹配有特定值的参数
  81. kwargs_matched = False
  82. for k,v in perm_kwargs.items(): #循环字典参数#crm_table_index':['URL','请求方法',[列表参数],{字典参数},],
  83. request_method_func = getattr(request, per_method) #反射 #请求方法 #GET #POST
  84. arg_val = request_method_func.get(k, None) # request字典中有此参数
  85. print("perm kwargs check:",arg_val,type(arg_val),v,type(v))
  86. if arg_val == str(v): #匹配上了特定的参数 及对应的 参数值, 比如,需要request 对象里必须有一个叫 user_id=3的参数
  87. kwargs_matched = True
  88. else:
  89. kwargs_matched = False
  90. break # 有一个参数不能匹配成功,则判定为假,退出该循环。
  91. else:
  92. kwargs_matched = True
  93.  
  94. #自定义权限钩子
  95. perm_func_matched = False
  96. if custom_perm_func: #如果有定义
  97. if custom_perm_func(request,args,kwargs):#def only_view_own_customers(request,*args,**kwargs):
  98. perm_func_matched = True
  99. else:
  100. perm_func_matched = False #使整条权限失效
  101. print('自定义权限钩子没有通过',perm_func_matched)
  102. else: #没有定义权限钩子,所以默认通过
  103. perm_func_matched = True
  104.  
  105. match_results = [args_matched,kwargs_matched,perm_func_matched] #列表
  106. print("匹配结果: ", match_results) # [True, True, True]
  107. if all(match_results): #都匹配上了 #都返回 True
  108. match_key = permission_key # 给 match_key = None 赋值
  109. break #跳出大循环
  110.  
  111. if all(match_results): #如果都匹配成功 #'crm_table_index':['table_index','GET',[],{},],
  112. app_name, *per_name = match_key.split('_') #先给app_name赋一个值,其他的值都给*per_name 'crm_table_index':
  113. print("权限名:",match_key,'权限:',match_results)#crm_010902_only_view_CourseRecord_POST [True, True, True]
  114. print('分割:',app_name, *per_name) # crm 010902 only view CourseRecord POST
  115. perm_obj = '%s.%s' % (app_name,match_key)#'crm.table_index' # url(r'^(\w+)/$', views.table_index, name='table_index'), # 单个具体app页面
  116. print("生成权限:",perm_obj) #crm.crm_010902_only_view_CourseRecord_POST
  117. if request.user.has_perm(perm_obj):
  118. print('当前用户有此权限')
  119. return True
  120. else:
  121. print('当前用户没有该权限')
  122. return False
  123. else:
  124. print("未匹配到权限项,当前用户无权限")
  125.  
  126. def check_permission(func):
  127. print('权限func',func)#权限func <function table_data_list at 0x030636A8> #循环 URL name
  128. def inner(*args,**kwargs):
  129. print('开始权限匹配:',type(args))
  130. request = args[0]#请求第一个
  131. print('判断登陆情况:')
  132. if request.user.id == None:
  133. print('未登陆')
  134. return redirect( '/gbacc/gbacc_login/' )#返回登陆页面
  135. else:
  136. if request.user.is_superuser == True:
  137. print('超级管理员')
  138. return func( *args, **kwargs ) #直接返回 真
  139. print( '已登陆,判断有perm_check(*args,**kwargs)去执行' )
  140. if not perm_check(*args,**kwargs): #如果返回不为真 #没权限
  141. print('#没权限',perm_check(*args,**kwargs))
  142. request = args[0]
  143. return HttpResponse('你没有这个权限')
  144. print('有权限',func(*args,**kwargs)) #<HttpResponse status_code=200, "text/html; charset=utf-8">
  145. return func(*args,**kwargs)
  146. print('inner',inner)
  147. return inner #返回 真或假
  148. # ————————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


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

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

  1. Django CRM客户关系管理系统

    CRM需求分析 随着信息化时代带来的科技创新,CRM客户关系管理系统带来的效益在已经成为很多企业提高竞争优势的一分部,CRM客户关系管理系统将企业管理和客户关系管理集成到统一的平台,其系统功能主要体现 ...

  2. Django项目:CRM(客户关系管理系统)--70--60PerfectCRM实现CRM学生上课记录

    #urls.py """PerfectCRM URL Configuration The `urlpatterns` list routes URLs to views. ...

  3. Django项目:CRM(客户关系管理系统)--74--64PerfectCRM实现CRM课程排名详情

    #urls.py """PerfectCRM URL Configuration The `urlpatterns` list routes URLs to views. ...

  4. Django项目:CRM(客户关系管理系统)--72--62PerfectCRM实现CRM讲师讲课记录

    #urls.py """PerfectCRM URL Configuration The `urlpatterns` list routes URLs to views. ...

  5. CRM客户关系管理系统-需求概设和详设

    大概设计 大概设计就是对需求进行一个整体性分析,把需要实现的功能都列出来,对于客户关系管理系统,我们需要从角色出发,从而确定有哪些需求,最好是画个思维导图 首先我们是为培训学校这么一个场景来开发的,所 ...

  6. CRM 客户关系管理系统

    CRM(Customer Relationship Manager)客户关系管理系统 企业为提高核心竞争力,利用相应的信息技术以及互联网技术协调企业与顾客间在销售.营销和服务上的交互,从而提升其管理方 ...

  7. CRM客户关系管理系统 北京易信软科信息技术有限公司

    北京易信软科信息技术有限公司 推出大型erp系统,库存管理系统,客户关系管理系统,车辆登记管理系统,员工管理系统,采购管理系统,销售管理系统,为您的企业提供最优质的产品服务 北京易信软科您可信赖的北京 ...

  8. Django项目:CRM(客户关系管理系统)--84--74PerfectCRM实现CRM权限和权限组限制访问URL

    #models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...

  9. Django项目:CRM(客户关系管理系统)--82--72PerfectCRM实现CRM动态菜单和角色

    #models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...

随机推荐

  1. win10 mysql5.7指定某个配置文件启动

    点击开始菜单,搜索cmd.exe,左击以管理员身份运行 C:\Users\Administrator>cd C:\Program Files\MySQL\MySQL Server 5.7\bin ...

  2. mavlink 笔记1

    Packet Anatomy This is the anatomy of one packet. It is inspired by the CAN and SAE AS-4 standards. ...

  3. PAT甲级——A1133 Splitting A Linked List【25】

    Given a singly linked list, you are supposed to rearrange its elements so that all the negative valu ...

  4. 豌豆荚Redis集群方案:Codis

    Codis简介 Codis是一个分布式Redis解决方案,对于上层的应用来说,连接到CodisProxy和连接原生的RedisServer没有明显的区别(不支持的命令列表),上层应用可以像使用单机的R ...

  5. 运算符的基本概念以及常用Scanner、随机数Random、选择结构的初步了解

    运算符 分类 算术运算符 位运算符 关系运算符|比较运算符 逻辑运算符 条件运算符 赋值运算符 其中优先级顺序从上到下,可以记忆口诀:单目乘除位关系,逻辑三目后赋值 操作数: 运算符左右两边的数 表达 ...

  6. vuex的使用入门-官方用例

    store/index.js import Vue from 'vue' import Vuex from 'vuex'; // 使用vuex Vue.use(Vuex) const store = ...

  7. <linux常用命令>初级版

    显示时间 date 显示日历cal 变换目录 cd 显示当前所在目录 pwd 建立新目录 mkdir -p a/b/c 删除空目录 rmdir 当前目录下文件和目录显示 ls 复制 cp 文件 路径 ...

  8. POJ 2954 /// 皮克定理+叉积求三角形面积

    题目大意: 给定三角形的三点坐标 判断在其内部包含多少个整点 题解及讲解 皮克定理 多边形面积s = 其内部整点in + 其边上整点li / 2 - 1 那么求内部整点就是 in = s + 1 - ...

  9. hudson通过ant自动编译、启动、停止java的jar

    set ANT_PATH=E:\soft\apache_ant\bine:cd E:\data\codex\server\trunk\serversvn up @echo.@echo.@echo &q ...

  10. windows 内核下获取进程路径

    windows 内核下获取进程路径 思路:1):在EPROCESS结构中获取.此时要用到一个导出函数:PsGetProcessImageFileName,申明如下: NTSYSAPI UCHAR *  ...