根据销售额制作客户报告

Making of a customer report based on sales

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

型号:


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

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

也许您正在寻找这个:

order_by() order_by(*字段)

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

示例:

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

了解更多信息 here

是的,这可以通过注释来完成,而且效率会更高,因为所有计算都是在单个查询中进行的,而不是 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是什么,所以你自己想办法或者修改问题。

P.S。您不必将日期隐藏到 filter_string - 您可以将任何类型的对象传递给模板,然后再传递给过滤器。