【问题标题】:Making of a customer report based on sales根据销售情况制作客户报告
【发布时间】:2021-07-13 06:06:50
【问题描述】:

我正在尝试制作一份客户明智的销售报告,其中将列出客户在所选时间段内发生的销售总数、总金额、支付总额和销售余额。

型号:


class Customer(models.Model):
    name = models.CharField(max_length=128)
    phone = models.CharField(max_length=128)
    email = models.EmailField(blank=True, null=True)
    address = models.TextField()
    is_deleted = models.BooleanField(default=False)
    ...


class Sale(models.Model):
    auto_id = models.PositiveIntegerField()
    sale_id = models.CharField(max_length=128, blank=True, null=True)
    sale_date = models.DateTimeField()

    customer = models.ForeignKey('customers.Customer', limit_choices_to={'is_deleted': False}, on_delete=models.CASCADE)
    customer_address = models.TextField(blank=True, null=True)
    sale_category = models.CharField(max_length=128, choices=SALE_CATEGORY, default="intra_state")

    subtotal = models.DecimalField(default=0.0, decimal_places=2, max_digits=15, validators=[MinValueValidator(Decimal('0.00'))])
    round_off = models.DecimalField(decimal_places=3, default=0.00, max_digits=30)
    total = models.DecimalField(default=0.0, decimal_places=2, max_digits=15, validators=[MinValueValidator(Decimal('0.00'))])
    paid = models.DecimalField(default=0.0, decimal_places=2, max_digits=15, validators=[MinValueValidator(Decimal('0.00'))])
    balance = models.DecimalField(decimal_places=2, default=0.00, max_digits=15)

    is_deleted = models.BooleanField(default=False)
    ...

我尝试的是传递在该时间段内发生销售的客户,并使用模板标签获取模板中每个客户的销售值

观看次数:

def customer_sales_report(request):
    from_date = request.GET.get('from_date')
    to_date = request.GET.get('to_date')

    filter_form = {
        'from_date': from_date,
        'to_date': to_date,
    }

    from_date = datetime.datetime.strptime(from_date, '%d/%m/%Y')
    to_date = datetime.datetime.strptime(to_date, '%d/%m/%Y')

    sales = Sale.objects.filter(sale_date__date__range=[from_date, to_date], is_deleted=False)
    customer_pks = list(sales.values_list('customer_id', flat=True))
    customers = Customer.objects.filter(pk__in=customer_pks, is_deleted=False)

    filter_string = f"{filter_form['from_date']},{filter_form['to_date']}"

    context = {
        'customers': customers,
        'filter_form': filter_form,
        'filter_string': filter_string,
        "title": 'Customer sales report',
    }

    return render(request, 'customers/customer_sales_report.html', context)

模板:

...
<table>
    <thead>
        <tr>
            <th style="width: 30px;">ID</th>
            <th>Name </th>
            <th>Phone </th>
            <td>Sales</td>
            <td>Total Amount</td>
            <td>Paid Amount</td>
            <td>Balance Amount</td>
            <td>Customer Balance</td>
        </tr>
    </thead>
    <tbody>
        {% load el_pagination_tags %}
        {% paginate 20 customers %}
        {% for instance in customers %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>
                <a class="" href="{% url 'customers:customer' pk=instance.pk %}" >{{ instance }}</a>
            </td>
            <td>{{ instance.phone }}</td>

            {% with instance.pk|get_customer_sales:filter_string as sales %}
            <td>{{ sales.total_count }}</td>
            <td>{{ sales.subtotal }}</td>
            <td>{{ sales.paid }}</td>
            <td>{{ sales.balance }}</td>
            <td>{{ sales.current_balance }} ({{ sales.current_balance_type }})</td>
            {% endwith %}
        </tr>
        {% endfor %}
    </tbody>

</table>
...

模板标签:


@register.filter
def get_customer_sales(pk, data):
    list_data = data.split(',')

    from_date = list_data[0]
    to_date = list_data[1]
    from_date = datetime.datetime.strptime(from_date, '%d/%m/%Y').date()
    to_date = datetime.datetime.strptime(to_date, '%d/%m/%Y').date()

    sales = Sale.objects.filter(customer_id=pk, sale_date__date__range=[from_date, to_date], is_deleted=False)
    subtotal_amount = sales.aggregate(Sum('total'))['total__sum']
    sale_payment = sales.aggregate(Sum('paid'))['paid__sum']
    sale_balance = sales.aggregate(Sum('balance'))['balance__sum']
    ...

    sale_data = {
        'total_count': sales.count(),
        'paid': sale_payment,
        'balance': sale_balance,
        'subtotal': subtotal_amount,
        "current_balance" : current_balance,
        "current_balance_type" : current_balance_type,
    }

    return sale_data

我现在需要的是按他们的总金额订购,到目前为止我还无法做到。有没有一种方法可以将总金额、已付款、销售余额注释到客户查询集中,这将使其更容易或任何其他方式

【问题讨论】:

    标签: python django report django-annotate


    【解决方案1】:

    是的,这可以通过注释来完成,而且效率更高,因为所有计算都是在单个查询中进行的,而不是 3 * NRows

    我们可以通过Filtering on annotations 实现这一目标。

    顺便说一句,customer_pks 不需要list(),让 DB 直接处理查询应该更有效。

    sales = Sale.objects.filter(sale_date__date__range=[from_date, to_date], is_deleted=False)
    customers = Customer.objects.filter(pk__in=sales.values('customer_id'), is_deleted=False)
    
    sales_q = Q(sales__sale_date__date__range=[from_date, to_date], sales__is_deleted=False)
    customers = customers.annotate(
        subtotal_amount=Sum('sales__total', filter=sales_q),
        sale_payment=Sum('sales__paid', filter=sales_q),
        sale_balance=Sum('sales__balance', filter=sales_q),
    )
    

    我不知道current_balancecurrent_balance_type是什么,所以你需要自己弄清楚或者修改问题。

    附:您不必将日期转换为 filter_string - 您可以将任何类型的对象传递给模板,然后传递给过滤器。

    【讨论】:

    • current_balance 没关系,我有它的功能。我有其他变量要传递给模板标签,只是显示想要的东西,一次只能传递 2 个,所以我将它们组合成一个字符串,只传递 2 个。
    • 那么以上解决了你的任务吗?如果是,请接受/点赞
    • 哦,我不知道过滤器仅限于 2 个参数...好吧,您始终可以将 dict/tuple 作为参数(即filter_form)传递以避免解析格式-解析循环并复制粘贴解析代码
    • 我还有一个疑问,因为我没有字段 discount_amount 我需要从subtotal - total 计算它,我也可以在 F() 中添加过滤器吗?
    • 不,您不能,但是,您可以在聚合后减去总和,例如 F('subtotal_amount') - F('sale_payment')。这应该也可以工作:Sum(F('sales__total') - F('sales__paid'), filter=sales_q)
    【解决方案2】:

    也许你正在寻找这个:

    order_by() order_by(*fields)

    默认情况下,QuerySet 返回的结果按照模型 Meta 中的 ordering 选项给出的 ordering tuple 进行排序。您可以使用 order_by 方法在每个 QuerySet 的基础上覆盖它。

    例子:

    Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
    

    阅读更多信息here

    【讨论】:

    • 实际上是但不是,我有一个客户查询集,我需要按照他们相应的聚合销售总额或余额总额进行排序,这些不是客户模型中的字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    相关资源
    最近更新 更多