Sayantan
Sayantan

Reputation: 335

Unique Invoice numbers in Django Views for Models

I have a django model for my invoices.

Now I need to generate unique invoice numbers for each day (in my Django Views function).

Example, invoice no, for 7th April, 2016 shall be like: 16040701, 16040702, 16040703, etc.

How can this be achieved?

Upvotes: 0

Views: 2232

Answers (2)

Shankar Balaji U
Shankar Balaji U

Reputation: 9

class SerialNumberField(CharField):
    _for = None

    def __init__(self, *args, **kwargs):
        self._for = kwargs.pop('_for', None)
        kwargs.setdefault('max_length', 20)
        kwargs.setdefault('editable', False)
        super().__init__(*args, **kwargs)

    def contribute_to_class(self, cls, name):
        super().contribute_to_class(cls, name)
        self.model = cls

    def generate_serial_number(self):
        today = timezone.now().date()
        today_obj = self.model.objects.filter(created_date=today)
        count = today_obj.count() + 1
        return f"#{self._for}{today.strftime('%Y%m%d')}-{count:03d}"

    def pre_save(self, model_instance, add):
        if not getattr(model_instance, self.attname):
            setattr(model_instance, self.attname, self.generate_serial_number())
        return super().pre_save(model_instance, add)

This field is simple to use as a serialnumberfield no need of maintaining the last bill count to put the next bill.

Upvotes: 0

Rob Vezina
Rob Vezina

Reputation: 638

I would do this by overriding save() in your Invoice model. First, add a field for your invoice number to your model:

invoice_id = models.CharField(blank=True, max_length=8)

Then, override the save() method:

def save(self, *args, **kwargs):
    today = datetime.date.today()
    today_string = today.strftime('%y%m%d')
    next_invoice_number = '01'
    last_invoice = Invoice.objects.filter(invoice_id__startswith=today_string).order_by('invoice_id').last()
    if last_invoice:
        last_invoice_number = int(last_invoice.invoice_id[6:])
        next_invoice_number = '{0:02d}'.format(last_invoice_number + 1)
    self.invoice_id = today_string + next_invoice_number
    super(Invoice, self).save(*args, **kwargs)

This will give you the format yymmdd## that you are looking for. Note: this will not work if you have more than 99 invoices per day. If you needed more than 99, change {0:02d} to {0:03d} and set max_length=9 on your invoice_id field. This will accommodate 999 invoices per day with the format yymmdd###.

Upvotes: 2

Related Questions