docs: def allocateFees(self):
          '''
          Fees are allocated across invoice items based on their discounted
          total price net of adjustments as a proportion of the overall
          invoice's total price
          '''
          items = list(self.invoiceitem_set.all())
  
          # Check that totals and adjusments match.  If they do not, raise an error.
          if self.total != sum([x.total for x in items]):
              msg = _('Invoice item totals do not match invoice total.  Unable to allocate fees.')
              logger.error(str(msg))
              raise ValidationError(msg)
          if self.adjustments != sum([x.adjustments for x in items]):
              msg = _('Invoice item adjustments do not match invoice adjustments.  Unable to allocate fees.')
              logger.error(str(msg))
              raise ValidationError(msg)
  
          for item in items:
              saveFlag = False
  
              if self.total - self.adjustments > 0:
                  item.fees = self.fees * ((item.total - item.adjustments) / (self.total - self.adjustments))
                  saveFlag = True
  
              # In the case of full refunds, allocate fees according to the
              # initial total price of the item only.
              elif self.total - self.adjustments == 0 and self.total > 0:
                  item.fees = self.fees * (item.total / self.total)
                  saveFlag = True
  
              # In the unexpected event of fees with no total, just divide
              # the fees equally among the items.
              elif self.fees:
                  item.fees = self.fees * (1 / len(items))
                  saveFlag = True
  
              if saveFlag:
                  item.save()