[Answer]-Using aggregation with post calculated field

1๐Ÿ‘

โœ…

I think you should redefine the Benefit model, add amount field which will be automatically calculated based on calculation_type and custom fields value in model save:

class Benefit(models.Model):
    employee = models.ForeignKey('Employee')

    # this field can be
    # Percentage (ex %2 from employee main salary)
    # Fixed Price (ex $150)
    # days
    calculation_type = thetopchoices(FIX,PER,DAYS)

    # this field should be the value 
    # of the percentage or the fixed amount
    custom = models.PositiveIntegerField(....)
    amount = models.PositiveIntegerField(...., editable=False) # auto calculated field in save

    def __init__(self, *args, **kwargs):
        super(Benefit, self).__init__(*args, **kwargs)
        self.__original_calc_type = self.calculation_type
        self.__original_custom = self.custom

    def calculate(self):
        employee = self.employee
        if self.calculation_type == 'PER':
            amount = employee.salary * self.custom
        elif self.calculation_type == 'FIX':
            amount = self.custom
        else
            amount = ( employee.salary / 30 ) * self.custom
        return amount

    def save(self, *args, **kwargs):
        recalculate = kwargs.pop('recalculate', False)
        if self.__original_calc_type != self.calculation_type or self.__original_custom != self.custom or recalculate:
            self.amount = self.calculate()
        super(Benefit, self).save(*args, **kwargs)
        self.__original_calc_type = self.calculation_type
        self.__original_custom = self.custom

Now to get the amount of all benefits is easy:

from django.db.models import Sum

class Employee(models.Model):
    ...
    ...

    @property
    def benefits_amount(self):
        d = self.benefit_set.aggregate(total_amount=Sum('amount'))
        return d['total_amount'] if d['total_amount'] else 0

If you want to update the benefits later based on any criteria you have, you need to do it like this:

for benefit in employee.benefit_set.all():
    benefit.save(recalculate=True)
๐Ÿ‘คAamir Rind

Leave a comment