Reputation: 41
I am trying to calculate the subtotal, VAT and Total for creating an invoice. I`ve got an error
unsupported operand type(s) for *: 'NoneType' and 'decimal.Decimal'
models.py
class InvoiceLine(models.Model):
TAX_RATE = (
(0, '20% (VAT on Expenses)'),
(1, '5% (VAT on Expenses)'),
(2, 'EC Aquisitions (20%)'),
(3, 'EC Aquisitions (Zero Rated)'),
(4, 'Exempt Expenses'),
(5, 'No VAT'),
(6, 'Reverse Charge Expenses (20%)'),
(7, 'Zero Rated Expenses'),
)
invoice = models.ForeignKey(Invoice,related_name="has_lines",on_delete=models.CASCADE, blank=True, null=True, unique=False)
invoice_item = models.CharField(max_length=100, verbose_name="Line")
tax_rate = models.IntegerField(choices=TAX_RATE,default=0, blank=True, null=True)
total = models.CharField(max_length=250, null=True, blank=True)
description = models.CharField(max_length=100, blank=True, null=True)
unit_price_excl_tax = models.DecimalField(max_digits=8,decimal_places=2, null=True, blank=True)
quantity = models.DecimalField(max_digits=8,decimal_places=2,default=1, null=True, blank=True)
unit_price = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
vat = models.CharField(max_length=250, null=True, blank=True)
def subtotal(self):
subtotal = Decimal(str(self.unit_price * self.quantity))
return subtotal.quantize(Decimal('0.01'))
def __unicode__(self):
return self.description
subtotal will calculate the unit price X quantity but give me an unsupported operand type error. Then, I`ll have the total_lines and VAT by adding 20%.
Can I just calculate them using?
def total(self):
total = Decimal(str(self.subtotal * (self.tax_rate/100)+ (self.tax_rate/100)))
return total.quantize(Decimal('0.01'))
Upvotes: 1
Views: 913
Reputation: 4819
The error says you are using a *
operation where the first number is actually not a number, but None
.
Since the last one is just a suggestion I assume the error will be on the first time you use it, when you calculate the subtotal.
def subtotal(self):
subtotal = Decimal(str(self.unit_price * self.quantity))
return subtotal.quantize(Decimal('0.01'))
And this would mean that unit_price is not set, thus is None
.
You can do different things to avoid the error. You can either define a default value for the unit_price field:
class InvoiceLine(models.Model):
TAX_RATE = (
(0, '20% (VAT on Expenses)'),
(1, '5% (VAT on Expenses)'),
(2, 'EC Aquisitions (20%)'),
(3, 'EC Aquisitions (Zero Rated)'),
(4, 'Exempt Expenses'),
(5, 'No VAT'),
(6, 'Reverse Charge Expenses (20%)'),
(7, 'Zero Rated Expenses'),
)
invoice = models.ForeignKey(Invoice,related_name="has_lines",on_delete=models.CASCADE, blank=True, null=True, unique=False)
invoice_item = models.CharField(max_length=100, verbose_name="Line")
tax_rate = models.IntegerField(choices=TAX_RATE,default=0, blank=True, null=True)
total = models.CharField(max_length=250, null=True, blank=True)
description = models.CharField(max_length=100, blank=True, null=True)
unit_price_excl_tax = models.DecimalField(max_digits=8,decimal_places=2, null=True, blank=True)
quantity = models.DecimalField(max_digits=8,decimal_places=2,default=1, null=True, blank=True)
unit_price = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True, default=0)
vat = models.CharField(max_length=250, null=True, blank=True)
You can also prevent the null value to happen if you don't allow null values at the database level:
class InvoiceLine(models.Model):
TAX_RATE = (
(0, '20% (VAT on Expenses)'),
(1, '5% (VAT on Expenses)'),
(2, 'EC Aquisitions (20%)'),
(3, 'EC Aquisitions (Zero Rated)'),
(4, 'Exempt Expenses'),
(5, 'No VAT'),
(6, 'Reverse Charge Expenses (20%)'),
(7, 'Zero Rated Expenses'),
)
invoice = models.ForeignKey(Invoice,related_name="has_lines",on_delete=models.CASCADE, blank=True, null=True, unique=False)
invoice_item = models.CharField(max_length=100, verbose_name="Line")
tax_rate = models.IntegerField(choices=TAX_RATE,default=0, blank=True, null=True)
total = models.CharField(max_length=250, null=True, blank=True)
description = models.CharField(max_length=100, blank=True, null=True)
unit_price_excl_tax = models.DecimalField(max_digits=8,decimal_places=2, null=True, blank=True)
quantity = models.DecimalField(max_digits=8,decimal_places=2,default=1, null=True, blank=True)
unit_price = models.DecimalField(max_digits=8, decimal_places=2, null=False, blank=False)
vat = models.CharField(max_length=250, null=True, blank=True)
Or, you could leave this part untouched and do a check on you subtotal calculation:
def subtotal(self):
if self.unit_price and self.quantity:
subtotal = Decimal(str(self.unit_price * self.quantity))
return subtotal.quantize(Decimal('0.01'))
else:
return None
Upvotes: 2