根据销售额制作客户报告
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_balance
和current_balance_type
是什么,所以你自己想办法或者修改问题。
P.S。您不必将日期隐藏到 filter_string
- 您可以将任何类型的对象传递给模板,然后再传递给过滤器。
我正在尝试制作一份客户明智的销售报告,其中将列出客户在选定时间段内的销售总数、总金额、已支付总额和销售余额。
型号:
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_balance
和current_balance_type
是什么,所以你自己想办法或者修改问题。
P.S。您不必将日期隐藏到 filter_string
- 您可以将任何类型的对象传递给模板,然后再传递给过滤器。