新手分享边爬文边写的 Django 用 admin 开发的简易进销存系统-3

2.财务(finance)模块

2.1.models.py 设定

2.1.1.应收帐款

当使用者产生一笔出货单时,系统需自动产生对应的应收帐款,应收帐款分单头单身。

RECEIVABLE_CHOICES = [
    ('N', u'尚未收款'),
    ('A', u'全部收款'),
    ('P', u'部分收款'),
    ('O', u'超额收款'),
]

class Receivable(models.Model):
    ship = models.ForeignKey(Ship, verbose_name=u'对应出货单', on_delete=models.CASCADE)
    customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT)
    is_active = models.BooleanField(verbose_name=u'是否有效', default=False)
    status = models.CharField(max_length=1, choices=RECEIVABLE_CHOICES, default='N', verbose_name=u'状态')
    receivabled = models.DateField(verbose_name=u'应收日期')
    created = models.DateTimeField(auto_now_add=True, verbose_name=u'建立时间')
    create_user = models.ForeignKey('auth.User', verbose_name=u'建立人员', on_delete=models.PROTECT)

    def get_absolute_url(self):
        return reverse('finance:receivable_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return '{}'.format(self.id)

    class Meta:
        verbose_name = '应收帐款'
        verbose_name_plural = verbose_name

2.1.2.应收帐款单身

class ReceivableDetail(models.Model):
    num = models.CharField(max_length=2, default='', verbose_name=u'单身项次')
    receivable = models.ForeignKey(Receivable, verbose_name=u'应收帐款单头', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, verbose_name=u'商品', on_delete=models.PROTECT)
    amount = models.DecimalField(max_digits=16, decimal_places=4, blank=False, verbose_name=u'金额')
    currency = models.ForeignKey(Currency, verbose_name=u'币别', on_delete=models.PROTECT)

    def save(self, *args, **kwargs):
        if self.num == '':
            #项次的格式是01,02...
            receivable_details = ReceivableDetail.objects.filter(receivable=self.receivable)
            num = "{0:02d}".format(receivable_details.count() + 1)
            self.num = "{0:02d}".format(int(num))

        super().save(*args, **kwargs)

    def __str__(self):
        return '{}'.format(self.num)

    class Meta:
        verbose_name = '应收帐款单身'
        verbose_name_plural = verbose_name

2.1.3.收款单

从我的第一篇新手分享边爬文边写的 Django 用 admin 开发的简易进销存系统-1的[4.1.销售流程]可以看到,一笔应收帐款可以对应到多笔收款单,收款单也分为单头与单身。

class Receive(models.Model):
    invoice_no = models.CharField(max_length=12, blank=False, null=False,
                                  verbose_name=u'发票号码', help_text=u'收款时必须登打发票号码')
    receivable = models.ForeignKey(Receivable, verbose_name=u'对应应收帐款',
                                   help_text=u'仅显示"有效"且非"全部收款"的应收帐款', on_delete=models.CASCADE)
    customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT)
    is_active = models.BooleanField(verbose_name=u'是否有效', default=True)
    is_delay = models.BooleanField(verbose_name=u'是否延迟', default=False)
    created = models.DateTimeField(auto_now_add=True, verbose_name=u'收款时间')
    create_user = models.ForeignKey('auth.User', verbose_name=u'建立人员', on_delete=models.PROTECT)

    def get_absolute_url(self):
        return reverse('finance:receive_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return '{}'.format(self.id)

    class Meta:
        verbose_name = '收款单'
        verbose_name_plural = verbose_name

2.1.4.收款单单身

class ReceiveDetail(models.Model):
    num = models.CharField(max_length=2, default='', verbose_name=u'单身项次')
    receive = models.ForeignKey(Receive, verbose_name=u'收款单单头', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, verbose_name=u'商品', on_delete=models.PROTECT)
    amount = models.DecimalField(max_digits=16, decimal_places=4, blank=False, verbose_name=u'金额')
    discount = models.DecimalField(max_digits=16, decimal_places=4, blank=False, null=False, verbose_name=u'折扣')
    currency = models.ForeignKey(Currency, verbose_name=u'币别', blank=False, null=False, on_delete=models.PROTECT)
    rate = models.DecimalField(max_digits=16, decimal_places=4, blank=False, null=False, verbose_name=u'汇率')
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)

    def save(self, *args, **kwargs):
        if self.num == '':
            #项次的格式是01,02...
            receive_details = ReceiveDetail.objects.filter(receive=self.receive)
            num = "{0:02d}".format(receive_details.count() + 1)
            self.num = "{0:02d}".format(int(num))

        super().save(*args, **kwargs)

    def __str__(self):
        return '{}'.format(self.num)

    class Meta:
        verbose_name = '收款单单身'
        verbose_name_plural = verbose_name

2.1.5.应付帐款

与2.1.1类似,当使用者产生一笔到货单时,系统需自动产生对应的应付帐款,应付帐款也分单头单身。

DUE_CHOICES = [
    ('N', u'尚未付款'),
    ('A', u'全部付款'),
    ('P', u'部分付款'),
    ('O', u'超额付款'),
]

class Due(models.Model):
    arrive = models.ForeignKey(Arrive, verbose_name=u'对应到货单', on_delete=models.CASCADE)
    supplier = models.ForeignKey(Supplier, verbose_name=u'供货商', on_delete=models.PROTECT)
    is_active = models.BooleanField(verbose_name=u'是否有效', default=False)
    status = models.CharField(max_length=1, choices=DUE_CHOICES, default='N', verbose_name=u'状态')
    dued = models.DateField(verbose_name=u'应付日期')
    created = models.DateTimeField(auto_now_add=True, verbose_name=u'建立时间')
    create_user = models.ForeignKey('auth.User', verbose_name=u'建立人员', on_delete=models.PROTECT)

    def get_absolute_url(self):
        return reverse('finance:due_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return '{}'.format(self.id)

    class Meta:
        verbose_name = '应付帐款'
        verbose_name_plural = verbose_name

2.1.6.应付帐款单身

class DueDetail(models.Model):
    num = models.CharField(max_length=2, default='', verbose_name=u'单身项次')
    due = models.ForeignKey(Due, verbose_name=u'应付帐款单头', on_delete=models.CASCADE)
    material = models.ForeignKey(Material, verbose_name=u'原料', on_delete=models.PROTECT)
    amount = models.DecimalField(max_digits=16, decimal_places=4, blank=False, verbose_name=u'金额')
    currency = models.ForeignKey(Currency, verbose_name=u'币别', on_delete=models.PROTECT)

    def save(self, *args, **kwargs):
        if self.num == '':
            #项次的格式是01,02...
            due_details = DueDetail.objects.filter(due=self.due)
            num = "{0:02d}".format(due_details.count() + 1)
            self.num = "{0:02d}".format(int(num))

        super().save(*args, **kwargs)

    def __str__(self):
        return '{}'.format(self.num)

    class Meta:
        verbose_name = '应付帐款单身'
        verbose_name_plural = verbose_name

2.1.7.付款单

一样从新手分享边爬文边写的 Django 用 admin 开发的简易进销存系统-1的[4.2.采购流程]可以看到,一笔应付帐款可以对应到多笔付款单,付款单也分为单头与单身。

class Pay(models.Model):
    invoice_no = models.CharField(max_length=12, blank=False, null=False,
                                  verbose_name=u'发票号码', help_text=u'付款时必须输入供货商提供的发票号码')
    due = models.ForeignKey(Due, verbose_name=u'对应应付帐款',
                            help_text=u'仅显示"有效"且非"全部付款"的应付帐款', on_delete=models.CASCADE)
    supplier = models.ForeignKey(Supplier, verbose_name=u'供货商', on_delete=models.PROTECT)
    is_active = models.BooleanField(verbose_name=u'是否有效', default=True)
    is_delay = models.BooleanField(verbose_name=u'是否延迟', default=False)
    created = models.DateTimeField(auto_now_add=True, verbose_name=u'付款时间')
    create_user = models.ForeignKey('auth.User', verbose_name=u'建立人员', on_delete=models.PROTECT)

    def get_absolute_url(self):
        return reverse('finance:pay_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return '{}'.format(self.id)

    class Meta:
        verbose_name = '付款单'
        verbose_name_plural = verbose_name

2.1.8.付款单单身

class PayDetail(models.Model):
    num = models.CharField(max_length=2, default='', verbose_name=u'单身项次')
    pay = models.ForeignKey(Pay, verbose_name=u'付款单单头', on_delete=models.CASCADE)
    material = models.ForeignKey(Material, verbose_name=u'原料', on_delete=models.PROTECT)
    amount = models.DecimalField(max_digits=16, decimal_places=4, blank=False, verbose_name=u'金额')
    discount = models.DecimalField(max_digits=16, decimal_places=4, blank=False, null=False, verbose_name=u'折扣')
    currency = models.ForeignKey(Currency, verbose_name=u'币别', blank=False, null=False, on_delete=models.PROTECT)
    rate = models.DecimalField(max_digits=16, decimal_places=4, blank=False, null=False, verbose_name=u'汇率')
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)

    def save(self, *args, **kwargs):
        if self.num == '':
            #项次的格式是01,02...
            pay_details = PayDetail.objects.filter(pay=self.pay)
            num = "{0:02d}".format(pay_details.count() + 1)
            self.num = "{0:02d}".format(int(num))

        super().save(*args, **kwargs)

    def __str__(self):
        return '{}'.format(self.num)

    class Meta:
        verbose_name = '付款单单身'
        verbose_name_plural = verbose_name

2.2.admin.py 设定

这里的话我相信有基础的人大概可以知道以下代码的作用,所以我就不说明了。

from django import forms
from django.contrib import admin
from .models import Due, DueDetail, Pay, PayDetail, Receivable, ReceivableDetail, Receive, ReceiveDetail
from purchase.models import ProcurementMaterial
from sale.models import OrderProduct
import datetime


class ReceivableDetailInline(admin.TabularInline):
    model = ReceivableDetail
    fields = ['product', 'amount', 'currency']
    extra = 0


class ReceivableAdmin(admin.ModelAdmin):
    list_display = ['id', 'ship', 'customer', 'is_active', 'status', 'receivabled', 'created', 'create_user']
    fields = ['ship', 'customer', 'is_active', 'status', 'create_user']
    inlines = [ReceivableDetailInline]
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100
    date_hierarchy = 'receivabled'


admin.site.register(Receivable, ReceivableAdmin)


"""
收款单单身检查
1.最少要有一个单身
2.收款金额是否至少一笔大于0
3.收款金额不得是负数
4.单身商品不得重复
"""
class ReceiveDetailCheckInlineFormset(forms.models.BaseInlineFormSet):
    def clean(self):
        detail_count = 0
        detail_amount = 0

        product_list = []
        for form in self.forms:
            if form.cleaned_data:
                detail_count += 1

                amount = form.cleaned_data.get('amount')
                if amount < 0:
                    raise forms.ValidationError(u'收款单中收款金额不得为负数。')
                elif amount > 0:
                    detail_amount += 1

                product = form.cleaned_data.get('product')
                if product.id in product_list:
                    raise forms.ValidationError(u"单身商品[{}-{}]收款已重复,"
                                                u"请重新填写收款单。".format(product.id, product.title))
                else:
                    product_list.append(product.id)

        if detail_count < 1:
            raise forms.ValidationError(u'您必须最少输入一笔收款单单身')
        if detail_amount < 1:
            raise forms.ValidationError(u'您必须最少一笔收款单单身金额大于0')


class ReceiveDetailInline(admin.TabularInline):
    formset = ReceiveDetailCheckInlineFormset
    model = ReceiveDetail
    fields = ['product', 'amount', 'discount', 'currency', 'rate', 'description']
    raw_id_fields = ['product', 'currency']
    extra = 0


"""
收款时的相关动作如下:
1.检查收款日期是否有延迟(is_delay)
2.检查应收帐款金额是否满足,决定应收帐款"状态",('A', u'全部收款'),('P', u'部分收款'),('O', '超额收款')
3.更新订单单身的已收含税金额(tax_receive)
"""
class ReceiveAdmin(admin.ModelAdmin):
    list_display = ['id', 'invoice_no', 'receivable', 'customer', 'is_active', 'created', 'create_user']
    fields = ['receivable', 'invoice_no']
    inlines = [ReceiveDetailInline]
    view_on_site = False
    list_per_page = 10
    list_max_show_all = 100
    date_hierarchy = 'created'

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'receivable':
            kwargs['queryset'] = Receivable.objects.filter(is_active=True).exclude(status='A')
        return super(ReceiveAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

    def save_model(self, request, obj, form, change):
        if not change:
            obj.create_user = request.user
            receivable = obj.receivable
            obj.customer = receivable.customer
        super().save_model(request, obj, form, change)

    def save_related(self, request, form, formsets, change):
        super().save_related(request, form, formsets, change)

        #决定对应应收帐款状态('A', '全部收款'),('P', '部分收款'),('O', '超额收款')
        # 如果有一个应收帐款单身金额没有全部出完的话,则状态为P
        receivable = form.cleaned_data.get('receivable')
        ship = receivable.ship
        order = ship.order
        receivable_details = ReceivableDetail.objects.filter(receivable=receivable)
        receives = Receive.objects.filter(receivable=receivable)
        status = 'A'
        for receivable_detail in receivable_details:
            product = receivable_detail.product
            order_products = OrderProduct.objects.filter(order=order, product=product)
            if order_products.count() > 0:
                order_product = order_products[0]
                received_amount = 0
                for receive in receives.all():
                    receive_details = ReceiveDetail.objects.filter(product=product, receive=receive)
                    if receive_details.all().count() > 0:
                        for receive_detail in receive_details.all():
                            received_amount += receive_detail.amount + receive_detail.discount

            if received_amount < receivable_detail.amount:
                status = 'P'
            else:
                if received_amount > receivable_detail.amount:
                    #如果有商品是部分收款P,就算是有超额收款也还是算成P
                    if status is 'P':
                        status = 'P'
                    else:
                        status = 'O'

        receivable.status = status
        receivable.save()

        #修改收款单状态是否有延迟
        receive = form.save(commit=False)
        today = datetime.datetime.now().date()
        if today > receivable.receivabled:
            receive.is_delay = True
        receive.save()


admin.site.register(Receive, ReceiveAdmin)


class DueDetailInline(admin.TabularInline):
    model = DueDetail
    fields = ['material', 'amount', 'currency']
    extra = 0


class DueAdmin(admin.ModelAdmin):
    list_display = ['id', 'arrive', 'supplier', 'is_active', 'status', 'dued', 'created', 'create_user']
    fields = ['arrive', 'supplier', 'is_active', 'status', 'dued', 'create_user']
    inlines = [DueDetailInline]
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100
    date_hierarchy = 'dued'


admin.site.register(Due, DueAdmin)


"""
付款单单身检查
1.最少要有一个单身
2.付款金额是否至少一笔大于0
3.付款金额不得是负数
4.单身原料不得重复
"""
class PayDetailCheckInlineFormset(forms.models.BaseInlineFormSet):
    def clean(self):
        detail_count = 0
        detail_amount = 0

        material_list = []
        for form in self.forms:
            if form.cleaned_data:
                detail_count += 1

                amount = form.cleaned_data.get('amount')
                if amount < 0:
                    raise forms.ValidationError(u'收款单中收款金额不得为负数。')
                elif amount > 0:
                    detail_amount += 1

                material = form.cleaned_data.get('material')
                if material.id in material_list:
                    raise forms.ValidationError(u"单身原料[{}-{}]付款已重复,"
                                                u"请重新填写付货单。".format(material.id, material.title))
                else:
                    material_list.append(material.id)

        if detail_count < 1:
            raise forms.ValidationError(u'您必须最少输入一笔付款单单身')
        if detail_amount < 1:
            raise forms.ValidationError(u'您必须最少一笔收款单单身金额大于0')


class PayDetailInline(admin.TabularInline):
    formset = PayDetailCheckInlineFormset
    model = PayDetail
    fields = ['material', 'amount', 'discount', 'currency', 'rate', 'description']
    raw_id_fields = ['material', 'currency']
    extra = 0


"""
付款时的相关动作如下:
1.检查付款日期是否有延迟(is_delay)
2.检查应付帐款金额是否满足,决定应付帐款"状态",('A', u'全部付款'),('P', u'部分付款'),('O', '超额付款')
3.更新采购单单身的已付含税金额(tax_pay)
4.付款单身如果有金额是0的则不存入数据库
"""
class PayAdmin(admin.ModelAdmin):
    list_display = ['id', 'invoice_no', 'due', 'supplier', 'is_active', 'is_delay', 'created', 'create_user']
    fields = ['due', 'invoice_no']
    inlines = [PayDetailInline]
    view_on_site = False
    list_per_page = 10
    list_max_show_all = 100
    date_hierarchy = 'created'

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'due':
            kwargs['queryset'] = Due.objects.filter(is_active=True).exclude(status='A')
        return super(PayAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

    def save_model(self, request, obj, form, change):
        if not change:
            obj.create_user = request.user
            due = obj.due
            obj.supplier = due.supplier
        super().save_model(request, obj, form, change)

    def save_related(self, request, form, formsets, change):
        super().save_related(request, form, formsets, change)

        #决定对应应付帐款状态('A', '全部付款'),('P', '部分付款'),('O', '超额付款')
        # 如果有一个应付帐款单身金额是超额付款的话,则状态为O
        due = form.cleaned_data.get('due')
        arrive = due.arrive
        procurement = arrive.procurement
        due_details = DueDetail.objects.filter(due=due)
        pays = Pay.objects.filter(due=due)
        status = 'A'
        for due_detail in due_details:
            material = due_detail.material
            procurement_materials = ProcurementMaterial.objects.filter(procurement=procurement, material=material)
            paid_amount = 0
            if procurement_materials.count() > 0:
                procurement_material = procurement_materials[0]
                for pay in pays.all():
                    pay_details = PayDetail.objects.filter(material=material, pay=pay)
                    if pay_details.all().count() > 0:
                        for pay_detail in pay_details.all():
                            paid_amount += pay_detail.amount + pay_detail.discount

            if paid_amount > due_detail.amount:
                status = 'O'
            else:
                if paid_amount < due_detail.amount:
                    #如果有商品是超额付款O,就算是有部分款也还是算成O
                    if status is 'O':
                        status = 'O'
                    else:
                        status = 'P'

        due.status = status
        due.save()

        #修改付款单状态是否有延迟
        pay = form.save(commit=False)
        today = datetime.datetime.now().date()
        if today > due.dued:
            pay.is_delay = True
        pay.save()


admin.site.register(Pay, PayAdmin)

2.3.templates 设定

如前面说到,当使用者新增一笔进货单时,系统会自动产生一笔应付帐款,如果应付帐款如下:
在这里插入图片描述
我希望在新增付款单时,信息填写方式如下:
1.先选择[对应应付帐款]
在这里插入图片描述
2.有了应付帐款单号后再显示该应付帐款的内容
在这里插入图片描述
然后我再去修改单身的付款金额。
以上的需求,我用jquery语法的方式完成,所以一样我用新增html的方式覆盖默认的change_form.html
在这里插入图片描述
change_form.html内容如下

{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_modify %}

{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{{ media }}
{% endblock %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}">{% endblock %}

{% block coltype %}colM{% endblock %}

{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %}

{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
&rsaquo; {% if add %}{% blocktrans with name=opts.verbose_name %}Add {{ name }}{% endblocktrans %}{% else %}{{ original|truncatewords:"18" }}{% endif %}
</div>
{% endblock %}
{% endif %}

{% block content %}<div id="content-main">
{% block object-tools %}
{% if change %}{% if not is_popup %}
  <ul class="object-tools">
    {% block object-tools-items %}
      {% change_form_object_tools %}
    {% endblock %}
  </ul>
{% endif %}{% endif %}
{% endblock %}
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.model_name }}_form" novalidate>{% csrf_token %}{% block form_top %}{% endblock %}
<div>
{% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %}
{% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %}
{% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
{% if errors %}
    <p class="errornote">
    {% if errors|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
    </p>
    {{ adminform.form.non_field_errors }}
{% endif %}

{% block field_sets %}
{% for fieldset in adminform %}
  {% include "./includes/fieldset.html" %}
{% endfor %}
{% endblock %}

{% block after_field_sets %}{% endblock %}

{% block inline_field_sets %}
{% for inline_admin_formset in inline_admin_formsets %}
    {% include inline_admin_formset.opts.template %}
{% endfor %}
{% endblock %}

{% block after_related_objects %}{% endblock %}

{% block submit_buttons_bottom %}{% submit_row %}{% endblock %}

{% block admin_change_form_document_ready %}
    <script type="text/javascript"
            id="django-admin-form-add-constants"
            src="{% static 'admin/js/change_form.js' %}"
            {% if adminform and add %}
                data-model-name="{{ opts.model_name }}"
            {% endif %}>
    </script>
{% endblock %}

{# JavaScript for prepopulated fields #}
{% prepopulated_fields_js %}

<script>
(function($) {
    $(document).ready(function(){
        var href = location.href;
        href_list = href.split('/');
        <!-- 表示为change -->
        if (href_list[href_list.length - 2] == 'change'){
            $('tr.add-row').hide();
            $('div.submit-row').html('<a href="/admin/finance/pay/" class="closelink">Close</a>');
            $('div.submit-row').show();
        }
        else{
            var $form = $('#pay_form');
            var formset_name = 'paydetail_set';
            var $formset_div = $('#' + formset_name + '-group');
            var $formset_table = $formset_div.find('table');
            var $formset_add_row_tr = $formset_div.find('tr.add-row')
            var $submit_row_div = $form.find('div.submit-row');
            var $formset_empty_row = $formset_table.find('tbody tr#' + formset_name + '-empty');
            var $formset_total_input = $formset_div.find('input#id_' + formset_name + '-TOTAL_FORMS')

            $submit_row_div.find('input').each(function(){
                $(this).click(function(){
                    $('#id_due').removeAttr("disabled");
                });
            });

            $formset_add_row_tr.hide();
            $submit_row_div.hide();

            if($('#id_due').val() == '')
            {
                <!-- 把非"对应应付帐款"的输入栏位隐藏起来 -->
                $form.find('fieldset:first>div').each(function(){
                    if(!$(this).hasClass('field-due')){
                        $(this).hide();
                    }
                })
                <!-- 隐藏"formset",""储存表单按钮"" -->
                $formset_div.hide();
                $submit_row_div.hide();

                <!-- 选择"对应应付帐款"之后 -->
                $('#id_due').change(function(){
                    var due_id = $(this).val();
                    if(due_id != ''){
                        $(this).attr("disabled","disabled");

                        <!-- 移除已有的付款单单身 -->
                        <!-- $formset_div.find('table tbody .form-row').remove(); -->

                        <!-- 根据对应应付帐款产生付款单单身 -->
                        $.get('{% url 'finance:due_ajax_detail_list' %}', {'id':due_id}, function(data){
                            if(data['code'] == 0){
                                $form.find('fieldset:first>div').each(function(){
                                    if(!$(this).hasClass('field-due')){
                                        $(this).show();
                                    }
                                })
                                $formset_div.show();
                                $submit_row_div.show();

                                <!-- 将资料填入表单中 -->
                                $tbody = $formset_table.find('tbody');
                                var dues = data['dues'];
                                var index = 0;
                                for(d in dues){
                                    total = $formset_total_input.val();
                                    $new_row = $formset_empty_row.clone(true);
                                    $formset_empty_row.removeClass('row' + (index + 1) % 3);
                                    $formset_empty_row.addClass('row' + (index + 2) % 3);
                                    $new_row.attr('id', formset_name + '-' + total);
                                    $new_row.removeClass('empty-form');
                                    $new_row.find('input').each(function(){
                                        name = $(this).attr('name');
                                        id = $(this).attr('id');
                                        $(this).attr('name', name.replace(/__prefix__/, index));
                                        $(this).attr('id', id.replace(/__prefix__/, index));
                                        name_list = name.split('-');
                                        if(name_list[name_list.length -1] == "material"){
                                            $(this).val(dues[d]['material']['id']);
                                            $(this).parent().append(dues[d]['material']['title']);
                                        }
                                        else if(name_list[name_list.length -1] == "amount"){
                                            $(this).val(dues[d]['amount']);
                                        }
                                        else if(name_list[name_list.length -1] == "discount"){
                                            $(this).val('0.0000');
                                        }
                                        else if(name_list[name_list.length -1] == "currency"){
                                            $(this).val(dues[d]['currency']);
                                        }
                                        else if(name_list[name_list.length -1] == "rate"){
                                            $(this).val(dues[d]['rate']);
                                        }
                                    });
                                    $new_row.find('a').remove();

                                    $formset_empty_row.before($new_row);

                                    total++;
                                    $formset_total_input.val(total);

                                    index++;
                                }

                                if (data['msg'] != '')
                                    alert(data['msg']);
                            }
                            else{
                                alert(data['msg']);
                            }
                        }, 'json')
                    }
                });
            }
            else{
                $submit_row_div.show();
                $('#id_due').attr("disabled","disabled");
            }
        }
    });
})(django.jQuery);
</script>
</div>
</form></div>
{% endblock %}

上图1中,在新增付款单画面载入时,只会先显示[对应应付帐款]的实作代码如下:

            if($('#id_due').val() == '')
            {
                <!-- 把非"对应应付帐款"的输入栏位隐藏起来 -->
                $form.find('fieldset:first>div').each(function(){
                    if(!$(this).hasClass('field-due')){
                        $(this).hide();
                    }
                })
                <!-- 隐藏"formset",""储存表单按钮"" -->
                $formset_div.hide();
                $submit_row_div.hide();
                ...

在选择好[对应应付账款]后,其余字段才会显示出来的实作代码如下:

                <!-- 选择"对应应付帐款"之后 -->
                $('#id_due').change(function(){
                    var due_id = $(this).val();
                    if(due_id != ''){
                        $(this).attr("disabled","disabled");
                        ...

在上图二中又可以看到,付款单单身字段除了显示在网页上之外,还将应付帐款的内容带了出来,实作的代码如下:

                        <!-- 根据对应应付帐款产生付款单单身 -->
                        $.get('{% url 'finance:due_ajax_detail_list' %}', {'id':due_id}, function(data){
                            if(data['code'] == 0){
                                $form.find('fieldset:first>div').each(function(){
                                    if(!$(this).hasClass('field-due')){
                                        $(this).show();
                                    }
                                })
                                $formset_div.show();
                                $submit_row_div.show();

                                <!-- 将资料填入表单中 -->
                                $tbody = $formset_table.find('tbody');
                                var dues = data['dues'];
                                var index = 0;
                                for(d in dues){
                                    total = $formset_total_input.val();
                                    $new_row = $formset_empty_row.clone(true);
                                    $formset_empty_row.removeClass('row' + (index + 1) % 3);
                                    $formset_empty_row.addClass('row' + (index + 2) % 3);
                                    $new_row.attr('id', formset_name + '-' + total);
                                    $new_row.removeClass('empty-form');
                                    $new_row.find('input').each(function(){
                                        name = $(this).attr('name');
                                        id = $(this).attr('id');
                                        $(this).attr('name', name.replace(/__prefix__/, index));
                                        $(this).attr('id', id.replace(/__prefix__/, index));
                                        name_list = name.split('-');
                                        if(name_list[name_list.length -1] == "material"){
                                            $(this).val(dues[d]['material']['id']);
                                            $(this).parent().append(dues[d]['material']['title']);
                                        }
                                        else if(name_list[name_list.length -1] == "amount"){
                                            $(this).val(dues[d]['amount']);
                                        }
                                        else if(name_list[name_list.length -1] == "discount"){
                                            $(this).val('0.0000');
                                        }
                                        else if(name_list[name_list.length -1] == "currency"){
                                            $(this).val(dues[d]['currency']);
                                        }
                                        else if(name_list[name_list.length -1] == "rate"){
                                            $(this).val(dues[d]['rate']);
                                        }
                                    });
                                    $new_row.find('a').remove();

                                    $formset_empty_row.before($new_row);

                                    total++;
                                    $formset_total_input.val(total);

                                    index++;
                                }

                                if (data['msg'] != '')
                                    alert(data['msg']);
                            }
                            else{
                                alert(data['msg']);
                            }
                        }, 'json')

这里可以看到是呼叫了视图函式(views.py),且必须设定urls.py。

                        $.get('{% url 'finance:due_ajax_detail_list' %}', {'id':due_id}, function(data){

除了付款单外,我也希望收款单也有相同的效果,所以收款单的change_form.html代码如下:

{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_modify %}

{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{{ media }}
{% endblock %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}">{% endblock %}

{% block coltype %}colM{% endblock %}

{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %}

{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
&rsaquo; {% if add %}{% blocktrans with name=opts.verbose_name %}Add {{ name }}{% endblocktrans %}{% else %}{{ original|truncatewords:"18" }}{% endif %}
</div>
{% endblock %}
{% endif %}

{% block content %}<div id="content-main">
{% block object-tools %}
{% if change %}{% if not is_popup %}
  <ul class="object-tools">
    {% block object-tools-items %}
      {% change_form_object_tools %}
    {% endblock %}
  </ul>
{% endif %}{% endif %}
{% endblock %}
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.model_name }}_form" novalidate>{% csrf_token %}{% block form_top %}{% endblock %}
<div>
{% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %}
{% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %}
{% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
{% if errors %}
    <p class="errornote">
    {% if errors|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
    </p>
    {{ adminform.form.non_field_errors }}
{% endif %}

{% block field_sets %}
{% for fieldset in adminform %}
  {% include "./includes/fieldset.html" %}
{% endfor %}
{% endblock %}

{% block after_field_sets %}{% endblock %}

{% block inline_field_sets %}
{% for inline_admin_formset in inline_admin_formsets %}
    {% include inline_admin_formset.opts.template %}
{% endfor %}
{% endblock %}

{% block after_related_objects %}{% endblock %}

{% block submit_buttons_bottom %}{% submit_row %}{% endblock %}

{% block admin_change_form_document_ready %}
    <script type="text/javascript"
            id="django-admin-form-add-constants"
            src="{% static 'admin/js/change_form.js' %}"
            {% if adminform and add %}
                data-model-name="{{ opts.model_name }}"
            {% endif %}>
    </script>
{% endblock %}

{# JavaScript for prepopulated fields #}
{% prepopulated_fields_js %}

<script>
(function($) {
    $(document).ready(function(){
        var $form = $('#receive_form');
        var formset_name = 'receivedetail_set';
        var $formset_div = $('#' + formset_name + '-group');
        var $formset_table = $formset_div.find('table');
        var $formset_add_row_tr = $formset_div.find('tr.add-row')
        var $submit_row_div = $form.find('div.submit-row');
        var $formset_empty_row = $formset_table.find('tbody tr#' + formset_name + '-empty');
        var $formset_total_input = $formset_div.find('input#id_' + formset_name + '-TOTAL_FORMS')

        $formset_add_row_tr.hide();
        $submit_row_div.hide();

        var href = location.href;
        href_list = href.split('/');
        <!-- 表示为change -->
        if (href_list[href_list.length - 2] == 'change'){
            $('div.submit-row').html('<a href="/admin/finance/receive/" class="closelink">Close</a>');
            $('div.submit-row').show();
        }
        else{
            $submit_row_div.find('input').each(function(){
                $(this).click(function(){
                    $('#id_receivable').removeAttr("disabled");
                });
            });

            if($('#id_receivable').val() == '')
            {
                <!-- 把非"对应应收帐款"的输入栏位隐藏起来 -->
                $form.find('fieldset:first>div').each(function(){
                    if(!$(this).hasClass('field-receivable')){
                        $(this).hide();
                    }
                })
                <!-- 隐藏"formset",""储存表单按钮"" -->
                $formset_div.hide();
                $submit_row_div.hide();

                <!-- 选择"对应应收帐款"之后 -->
                $('#id_receivable').change(function(){
                    var receivable_id = $(this).val();
                    if(receivable_id != ''){
                        $(this).attr("disabled","disabled");

                        <!-- 移除已有的收款单单身 -->
                        <!-- $formset_div.find('table tbody .form-row').remove(); -->

                        <!-- 根据对应应收帐款产生收款单单身 -->
                        $.get('{% url 'finance:receivable_ajax_detail_list' %}', {'id':receivable_id}, function(data){
                            if(data['code'] == 0){
                                $form.find('fieldset:first>div').each(function(){
                                    if(!$(this).hasClass('field-receivable')){
                                        $(this).show();
                                    }
                                })
                                $formset_div.show();
                                $submit_row_div.show();

                                <!-- 将资料填入表单中 -->
                                $tbody = $formset_table.find('tbody');
                                var receivables = data['receivables'];
                                var index = 0;
                                for(r in receivables){
                                    total = $formset_total_input.val();
                                    $new_row = $formset_empty_row.clone(true);
                                    $formset_empty_row.removeClass('row' + (index + 1) % 3);
                                    $formset_empty_row.addClass('row' + (index + 2) % 3);
                                    $new_row.attr('id', formset_name + '-' + total);
                                    $new_row.removeClass('empty-form');
                                    $new_row.find('input').each(function(){
                                        name = $(this).attr('name');
                                        id = $(this).attr('id');
                                        $(this).attr('name', name.replace(/__prefix__/, index));
                                        $(this).attr('id', id.replace(/__prefix__/, index));
                                        name_list = name.split('-');
                                        if(name_list[name_list.length -1] == "product"){
                                            $(this).val(receivables[r]['product']['id']);
                                            $(this).parent().append(receivables[r]['product']['title']);
                                        }
                                        else if(name_list[name_list.length -1] == "amount"){
                                            $(this).val(receivables[r]['amount']);
                                        }
                                        else if(name_list[name_list.length -1] == "discount"){
                                            $(this).val('0.0000');
                                        }
                                        else if(name_list[name_list.length -1] == "currency"){
                                            $(this).val(receivables[r]['currency']);
                                        }
                                        else if(name_list[name_list.length -1] == "rate"){
                                            $(this).val(receivables[r]['rate']);
                                        }
                                    });
                                    $new_row.find('a').remove();

                                    $formset_empty_row.before($new_row);

                                    total++;
                                    $formset_total_input.val(total);

                                    index++;
                                }

                                if (data['msg'] != '')
                                    alert(data['msg']);
                            }
                            else{
                                alert(data['msg']);
                            }
                        }, 'json')
                    }
                });
            }
            else{
                $submit_row_div.show();
                $('#id_receivable').attr("disabled","disabled");
            }
        }
    });
})(django.jQuery);
</script>
</div>
</form></div>
{% endblock %}

2.4.urls.py 设定

from django.urls import path
from django.contrib.auth.decorators import login_required
from . import views

app_name = 'finance'

urlpatterns = [
    path('receivable/ajax/list/', views.receivable_ajax_detail_list, name='receivable_ajax_detail_list'),
    path('due/ajax/list/', views.due_ajax_detail_list, name='due_ajax_detail_list'),
]

2.5.views.py 设定

views中有两个函式,功能就是在带出付款单单身收款单单身对应的应付帐款单身应收帐款单身内容。

from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from .models import Due, DueDetail, Pay, PayDetail, Receivable, ReceivableDetail, Receive, ReceiveDetail


def receivable_ajax_detail_list(request):
    return_dict = {}
    #判断使用者是否有权限检视应收帐款
    if request.user.has_perm('finance.view_receivable'):
        receivable_id = request.GET.get('id')
        receivable = Receivable.objects.get(id=receivable_id)
        return_dict['code'] = 0
        return_dict['msg'] = ''
        return_dict['receivables'] = []
        receivable_details = ReceivableDetail.objects.filter(receivable=receivable)

        for d in receivable_details.all():
            product = d.product
            amount = d.amount
            currency = d.currency
            rate = currency.rate

            # 如果该应收帐款有其他对应收款,则需扣掉已收款的商品金额
            other_receives = Receive.objects.filter(receivable=receivable, is_active=True)
            if other_receives.count() > 0:
                return_dict['msg'] = u'此应收帐款已有对应收款单,收款单单号如下:'
                for r in other_receives.all():
                    return_dict['msg'] += ' ' + str(r.id)
                    receive_detail = ReceiveDetail.objects.filter(receive=r, product=product)
                    if receive_detail.all().count() > 0:
                        amount -= receive_detail[0].amount

            if amount != 0:
                product_info = {'id': product.id, 'title': product.title}
                product_dict = {'product': product_info, 'amount': amount, 'currency': currency.id, 'rate': rate}
                return_dict['receivables'].append(product_dict)
    else:
        return_dict['code'] = 1
        return_dict['msg'] = u"您无权限浏览应收帐款"
    return JsonResponse(return_dict)


def due_ajax_detail_list(request):
    return_dict = {}
    #判断使用者是否有权限检视应付帐款
    if request.user.has_perm('finance.view_due'):
        due_id = request.GET.get('id')
        due = Due.objects.get(id=due_id)
        return_dict['code'] = 0
        return_dict['msg'] = ''
        return_dict['dues'] = []
        due_details = DueDetail.objects.filter(due=due)

        for d in due_details.all():
            material = d.material
            amount = d.amount
            currency = d.currency
            rate = currency.rate

            # 如果该应付帐款有其他对应付款,则需扣掉已付款的金额
            other_pays = Pay.objects.filter(due=due, is_active=True)
            if other_pays.count() > 0:
                return_dict['msg'] = u'此应付帐款已有对应付款单,付款单号如下:'
                for p in other_pays.all():
                    return_dict['msg'] += ' ' + str(p.id)
                    pay_detail = PayDetail.objects.filter(pay=p, material=material)
                    if pay_detail.all().count() > 0:
                        amount -= pay_detail[0].amount

            if amount != 0:
                material_info = {'id': material.id, 'title': material.title}
                material_dict = {'material': material_info, 'amount': amount, 'currency': currency.id, 'rate': rate}
                return_dict['dues'].append(material_dict)
    else:
        return_dict['code'] = 1
        return_dict['msg'] = u"您无权限浏览应付帐款"
    return JsonResponse(return_dict)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值