django - 发票表单 - 验证保存前的子总计和净总计

时间:2018-04-19 16:18:23

标签: django validation invoice inline-formset

我有一张由两种型号组成的发票表格 - 发票和发票。 InvoiceItem - 在inlineformset_factory的帮助下。

我有以下jquery片段,通过读取每个项目的价格,数量,税来计算个别总计和净总额。

function calculateSubTotal(obj){
    subTotal = 0 

    parentDiv = obj.closest('.formset')

    rate=parseFloat($(parentDiv).find('.rate').val())
    quantity=parseInt($(parentDiv).find('.quantity').val())
    tax=$(parentDiv).find('.tax option:selected').html()//.

    tax=tax.match(/\d+/);
    if(tax)
        tax=parseFloat(tax[0],10)
    else
        return

    if(!isNaN(rate) && !isNaN(quantity) && $.isNumeric(tax)){
        subTotal = rate*quantity*(100+tax)/100
        $(parentDiv).find('.total').val(subTotal)
    }
}

function calculateTotal() {
    subTotal=0
    $('.total').each(function(){
        //console.log($(this).id)
        console.log($(this).val())
        val=parseFloat($(this).val())
        subTotal+=val
    });
    if(!isNaN(subTotal))
        $('#id_total').val(subTotal)
}
$(document).ready(function() {
    $('.formset .form-control').on("blur",function(e){
        calculateSubTotal(this);
        calculateTotal();
    });

});

现在,我“相信”,我需要在保存之前在服务器端进行所有这些计算,以防止用户在表单中进行任何手动更正/错误。 (如果我错了,请纠正我)

我如何继续?

这是我的CreateView的form_valid()。

def form_valid(self, form):
    context = self.get_context_data()
    item_formset = context['item_formset']
    with transaction.atomic():
        form.instance.invoice_type=self.kwargs['invoice_type']
        self.object = form.save(commit=False)
        #self.object.save()
        if item_formset.is_valid():
            forms = item_formset.save(commit=False)

            for form in forms:
                **#calculate sub-total and assign net-total to parentform.instance.total**
            item_formset.instance = self.object
            item_formset.save()

    return super().form_valid(form)

2 个答案:

答案 0 :(得分:0)

最干净的方法可能是为InvoiceInvoiceItem创建自定义模型方法,然后在表单上save()或在您的视图{{1}中调用它们}}

示例form_vaild()

models.py

然后在class Invoice(models.Model): customer = models.ForeignKey() date = models.DateField() total = models.DecimalField() def process_invoice(self): items = InvoiceItem.objects.filter(invoice=self) for item in items: ... process item .... item.save() self.total = InvoiceItem.objects.filter(invoice=self).values('line_total').aggregate(tot=Sum('line_total')['tot'] ... add whatever other logic you need ... self.save() 中,您可以通过form_valid调用该方法。

答案 1 :(得分:0)

围绕模型的大量试验和错误保存(),保存后信号,形成干净()等等,最后得到了一些有用的东西。

以下是它现在的样子。

  1. 首先,使用InvoiceItemForm的{​​{1}}方法确保每行的总数正确

    def clean(self):     cleaning_data = super(InvoiceItemForm,self).clean()

    clean()
  2. 接下来,在CreateViews的form_valid()方法下,遍历formset中的每个表单并对各个总计求和。将其与主表单的总值进行比较。

    with transaction.atomic():             form.instance.invoice_type = self.kwargs [' invoice_type']             self.object = form.save(commit = False)

    total=cleaned_data.get('total')
    if total:
    
        tax=cleaned_data.get('tax')
        calculated_total=price*(100+tax.rate)*quantity/100
        if calculated_total != total:
            raise forms.ValidationError({'total':["Total is incorrect."]})
        return  cleaned_data
    
  3. (欢迎任何可能的更正/简化)

    感谢。