• python+Django CRM客户关系管理系统开发(十四)--报名流程开发


    一、本节目标

    前几节我们开发了数据展示,增删改查,本节开始开发业务流程,报名流程。

    二、需求分析

    1、报名流程如以下描述:

    • 销售   发起报名流程,选择班级,发报名链接给学员
    • 学员   填写在线报名表,提交个人信息,上传证件信息,同意培训协议
    • 销售    审核报名表,审核通过后,创建一条缴费记录,自动把学员添加到相应的班级,报名成功

    三、功能开发

    1、表设计

    因为需要存储学生报名,缴费信息,因此需要设计表结构,同时合同信息也需要表来存储,因此添加model

    class ContractTemplate(models.Model):
    '''存储合同模板'''
    name = models.CharField(max_length=64)
    content = models.TextField()
    date = models.DateField(auto_now_add=True)

    class StudentEnrollment(models.Model):
    '''学员报名表'''
    customer = models.ForeignKey('CustomerInfo',on_delete=models.CASCADE)
    class_grade = models.ForeignKey('ClassList',on_delete=models.CASCADE)
    consultant = models.ForeignKey('UserProfile',on_delete=models.CASCADE)
    contract_agreed = models.BooleanField(default=False)
    contract_signed_date = models.DateTimeField(blank=True,null=True)
    contract_approved = models.BooleanField(default=False)
    contract_approved_date = models.DateTimeField('合同审核时间',blank=True,null=True)

    class Meta:
    unique_together = ('customer','class_grade')

    def __str__(self):
    return '%s'%self.customer

    class PaymentRecord(models.Model):
    '''存储学员缴费记录'''
    enrollment = models.ForeignKey('StudentEnrollment',on_delete=models.CASCADE)
    payment_type_choices = ((0,'报名费'),(1,'学费'),(2,'退费'))
    payment_type = models.SmallIntegerField(choices=payment_type_choices,default=0)
    amount = models.IntegerField('费用',default=500)
    consultant = models.ForeignKey('UserProfile',on_delete=models.CASCADE)
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
    return '%s'%self.enrollment

     

    2、按照流程,开发报名流程页面:

    销售人员根据学员id,以及班级名称,生成一个报名链接:

    在crm应用下,添加url:

     编写视图函数:

     创建一个名为:stu_enrollment的前端页面:

    <link href="/static/css/bootstrap.css" rel="stylesheet">
    <body>
    <h3>学员报名页</h3>
    <form class="form-horizontal" method="post">
    {% csrf_token %}
    <div class="form-group">
    <label for="inputEmail3" class="col-sm-2 control-label">客户</label>
    <div class="col-sm-10">
    <select name="customer_id" class="form-control">
    {% for customer in customers %}
    <option value="{{ customer.id }}">{{ customer.name }}</option>
    {% endfor %}
    </select>
    </div>
    </div>

    <div class="form-group">
    <label for="inputEmail3" class="col-sm-2 control-label">报名班级</label>
    <div class="col-sm-10">
    <select name="class_grade_id" class="form-control">
    {% for class_grade in class_lists %}
    <option value="{{ class_grade.id }}">{{ class_grade }}</option>
    {% endfor %}
    </select>
    </div>
    </div>
    <input type="submit" class="btn btn-success pull-right" value="下一步">
    </form>

    {% if enrollment_link %}
    <p>请将此报名链接复制并发送给学员填写 {{ enrollment_link }}</p>
    {% endif %}

    </body>

    效果如图:

     

    3、开发学员填写注册信息页面:

    学员填写注册信息,需要有一个页面,因此,还是在crm应用下,首先添加url:

    customerinfo添加如下字段:

    在crm创建from.py文件,生成customerinfo的form

    防止用户通过前端改html代码的方式改只读字段的信息,所以在form.py里面添加了一个自定义的验证方法(clean),如果只读字段提交的时候信息跟数据库中默认的不一样,就报错

    from django import forms
    from django.forms import ModelForm
    from crm import models

    class CustomerForm(ModelForm):
    class Meta:
    model = models.CustomerInfo
    fields = "__all__"
    #不显示的字段
    exclude = ['consult_content','status','consult_courses']
    #只读的字段
    readonly_fields = ['contact_type','contract','consultant','referral_from','source']

    #Django是通过“__new__”方法,找到ModelForm里的每个字段的,然后循环处每个字段添加自定义样式
    def __new__(cls, *args, **kwargs):
    #cls.base_fields是一个元组,里面的数据结构是 [(字段名,字段的对象),(),()]
    for field_name in cls.base_fields:
    field_obj = cls.base_fields[field_name]
    #添加属性
    field_obj.widget.attrs.update({'disable':'true'})
    return ModelForm.__new__(cls)

    #只读字段不让用户通过浏览器改HTML代码的方式修改
    def clean(self):
    #表单级别的错误
    if self.errors:
    raise forms.ValidationError(("please fix errors before re-submit"))
    #如果有instance id,表名这是一个修改的表单,应该检查只读字段
    if self.instance.id is not None:
    #取出只读字段,是一个字符串形式
    for field in self.Meta.readonly_fields:
    #通过反射取出字段的值(数据库里的数据)
    old_field_val = getattr(self.instance,field)
    #提交过来的数据
    form_val = self.cleaned_data.get(field)
    #如果两个数据不匹配
    if old_field_val != form_val:
    #提示只读字段不能修改
    #add_error是字段级别的错误提示
    self.add_error(field,"Readonly Field:field should be '{value}',not '{new_value}'".format(**{'value':old_field_val,'new_value':form_val}))

    编写视图函数:

     前端页面:

    <link href="/static/css/bootstrap.css" rel="stylesheet">

    <body>

    <div class="container">
    <h3>在线报名信息填写</h3>

    <div class="panel panel-primary">
    <div class="panel-heading">
    <h3 class="panel-title">学员在线报名</h3>
    </div>

    <div class="panel-body">

    <form class="form" method="post" onsubmit="return BeforeFormSubmit(this)">
    {% csrf_token %}
    {% for field in customer_form %}
    <div class="form-group col-lg-6">
    <label class="col-sm-2 control-label">{{ field.label }}</label>
    <div class="col-sm-10">
    {{ field }}
    <span style="color: red;">{{ field.errors.0 }}</span>
    </div>
    </div>
    {% endfor %}

    <div class="form-group col-lg-6">
    <label class="col-sm-2 control-label">报名班级</label>
    <div class="col-sm-10">
    {{ enrollment_obj.class_grade }}
    </div>
    </div>

    <div class="form-group col-lg-6">
    <label class="col-sm-2 control-label">学费</label>
    <div class="col-sm-10">
    {{ enrollment_obj.class_grade.course.price }}
    </div>
    </div>

    <div class="col-sm-offset-11 col-sm-2">
    <input type="submit" class="btn btn-success " value="提交">
    </div>

    </form>

    </div>

    <div class="panel-footer"><a href="http://www.fafafa.com"></a></div>
    </div>


    </div>

    <script>

    function BeforeFormSubmit(ele) {
    $(":disabled").removeAttr("disabled");
    }

    </script>

    页面效果如图:

    4、如果修改了只读字段,会提示错误:

    5、开发学生签署合同信息以及上传证件照片功能

    首先,添加一个上传文件的url:

    建一个存储上传文件的文件夹:

    在settings里添加上传文件路径:

    CRM_FILE_UPLOAD_DIR = os.path.join(BASE_DIR,'crm/upload_files/enrollment_data')

    编写视图函数:

    @csrf_exempt
    def enrollment_fileupload(request,enrollment_id):
    '''学员报名文件上传'''
    enrollment_upload_dir = os.path.join(conf.settings.CRM_FILE_UPLOAD_DIR,enrollment_id)
    #第一次上传图片时创建目录,学员上传第二张图片的时候,会判断目录是否存在
    #如果目录存在还继续mkdir就会报错,所以这里要做判断
    if not os.path.isdir(enrollment_upload_dir):
    os.mkdir(enrollment_upload_dir)
    #获取上传文件的对象
    file_obj = request.FILES.get('file')
    #最多只允许上传3个文件
    if len(os.listdir(enrollment_upload_dir)) <= 3:
    #把图片名字拼接起来(file.name:上传的文件名字)
    with open(os.path.join(enrollment_upload_dir,file_obj.name),'wb') as f:
    for chunks in file_obj.chunks():
    f.write(chunks)
    else:
    return HttpResponse(json.dumps({'status':False,'err_msg':'最多只能上传三个文件'}))
    return HttpResponse(json.dumps({'status':True}),)

    前端页面完善修改:

    这里使用到了dropzone: https://www.dropzonejs.com/#installation,下载将css和js文件放到static里:

    9、点击后提示报名成功:

    10、接下来该审核合同了

    首先,添加审核的url:

    编写视图函数:

    def contract_audit(request,enrollment_id):
    enrollment_obj = models.StudentEnrollment.objects.get(id=enrollment_id)
    if request.method == 'POST':
    enrollment_form = form.EnrollmentForm(instance=enrollment_obj, data=request.POST)
    if enrollment_form.is_valid():
    enrollment_form.save()
    stu_obj = models.Student.objects.get_or_create(customer=enrollment_obj.customer)[0]
    # m2m, 添加班级
    stu_obj.class_grades.add(enrollment_obj.class_grade_id)
    stu_obj.save()
    # 改变报名
    enrollment_obj.customer.status = 1
    enrollment_obj.save()
    return redirect("/backadmin/crm/customerinfo/%s/change" % enrollment_obj.customer.id)
    else:
    # 拿到客户信息的表单
    customer_form = form.CustomerForm(instance=enrollment_obj.customer)
    enrollment_form = form.EnrollmentForm(instance=enrollment_obj)
    return render(request, 'contract_audit.html', locals())

    添加enrollment的form

    class EnrollmentForm(ModelForm):
    class Meta:
    model = models.StudentEnrollment
    fields = '__all__'

    def __new__(cls, *args, **kwargs):
    # cls.base_fields是一个元组,里面是 所有的 【(字段名,字段的对象),(),()】
    for field_name in cls.base_fields:
    # 获取每个字段的对象
    field_obj = cls.base_fields[field_name]
    # 添加属性
    field_obj.widget.attrs.update({'class': 'form-control'})
    return ModelForm.__new__(cls)

    设计html页面:

    <h3>学员报名|合同审核</h3>

    <form class="form-horizontal" method="post" onsubmit="BeforeFormSubmit(this)">{% csrf_token %}

    {{ customer_form }}
    {{ enrollment_form }}

    <input type="submit" class="btn btn-success pull-right" value="审核通过" >

    </form>

    <script>
    function BeforeFormSubmit(ele) {
    $(":disabled").removeAttr("disabled");
    }

    </script>

    效果如图:

  • 相关阅读:
    mysql备份还原
    JavaScript位移运算多个大于号的使用方法
    js with 语句的用法
    公告栏文字滚动
    Tar打包、压缩与解压缩到指定目录的方法
    域名跳转汇总文章
    linux常用命令大全
    nginx添加多站点
    linux一键安装php环境
    linux安装unzip及使用
  • 原文地址:https://www.cnblogs.com/realizetomoney/p/13942147.html
Copyright © 2020-2023  润新知