You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django后端视图中如何更新客户付款日期以避免生成重复账单

Django CRM 账单生成与缴费日期更新解决方案

首先确保你的Customer模型已新增缴费周期字段,示例定义如下:

from django.db import models

class Customer(models.Model):
    # 原有其他字段保留
    name = models.CharField(max_length=100)
    next_payment = models.DateField(verbose_name="下次缴费日期")
    recuring_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="周期缴费金额")
    # 新增缴费周期字段,可选月度/季度
    billing_cycle = models.CharField(
        max_length=10,
        choices=[('month', '月度'), ('quarter', '季度')],
        default='month',
        verbose_name="缴费周期"
    )

新增字段后执行以下命令同步数据库:

python manage.py makemigrations
python manage.py migrate

之后修改refresh_dashboard视图代码如下,需提前安装python-dateutil库处理日期偏移(执行pip install python-dateutil安装):

from datetime import date
from dateutil.relativedelta import relativedelta
from django.shortcuts import redirect
from .models import Customer, Bill

def refresh_dashboard(request):
    today = date.today()
    # 仅筛选已到缴费日期的客户,减少不必要的遍历
    due_customers = Customer.objects.filter(next_payment__lte=today)
    for customer in due_customers:
        # 双重校验:同缴费周期内已生成未缴账单则跳过,避免重复
        cycle_start_month = (customer.next_payment.month // 3)*3 +1 if customer.billing_cycle == 'quarter' else customer.next_payment.month
        cycle_end_month = (customer.next_payment.month //3)*3 +3 if customer.billing_cycle == 'quarter' else customer.next_payment.month
        existing_bill = Bill.objects.filter(
            name=customer.name,
            status="unpaid",
            generate_date__year=customer.next_payment.year,
            generate_date__month__gte=cycle_start_month,
            generate_date__month__lte=cycle_end_month
        ).exists()
        if existing_bill:
            continue
        # 生成新账单
        Bill.objects.create(
            name=customer.name,
            status="unpaid",
            price=customer.recuring_amount,
            generate_date=today
        )
        # 按缴费周期更新下次缴费日期
        if customer.billing_cycle == 'month':
            customer.next_payment += relativedelta(months=1)
        else:
            customer.next_payment += relativedelta(months=3)
        customer.save()
    return redirect('/')

核心优化点:

  • 废弃原有的字符串格式日期比较逻辑,直接用Django ORM原生日期过滤,性能更高且不会出现格式匹配错误
  • 新增同周期账单重复校验逻辑,即使用户多次点击刷新按钮,也不会在同一个缴费周期内生成重复账单
  • 去掉对eligible字段的强制依赖,账单生成后自动更新下次缴费日期,只有到达新的缴费日期才会触发下一次账单生成,从根源避免重复生成问题
  • 优化遍历逻辑,仅筛选到期客户,不需要遍历全量客户数据,大用户量场景下性能提升明显

如果需要保留eligible字段的手动控制能力,仅需要在due_customers的过滤条件中新增eligible=True即可,逻辑完全兼容。

内容的提问来源于stack exchange,提问作者sarangkkl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 05:27:02