How to recalculate a field in another model based on the calculations of one model in Django?

0

Issue

There are three models in my project, that are:

class Package(models.Model):
    patient=models.ForeignKey(Patient, on_delete=CASCADE)
    diagnosis=models.ForeignKey(Diagnosis, on_delete=CASCADE)
    treatment=models.ForeignKey(Treatment, on_delete=CASCADE)
    patient_type=models.ForeignKey(PatientType, on_delete=CASCADE)
    date_of_admission=models.DateField(default=None)
    max_fractions=models.IntegerField(default=None)
    total_package=models.DecimalField(max_digits=10, decimal_places=2)

class Receivables(models.Model):
    patient=models.ForeignKey(Patient, on_delete=CASCADE)
    pattern = RegexValidator(r'(RT|rt|rT|Rt)\/[0-9]{4}\/[0-9]{2}\/[0-9]{4}', 'Enter RT Number properly!')
    rt_number=models.CharField(max_length=15, validators=[pattern])
    discount=models.DecimalField(max_digits=9, decimal_places=2, default=0)
    approved_package=models.DecimalField(max_digits=10, decimal_places=2, default=0)
    proposed_fractions=models.IntegerField()
    done_fractions=models.IntegerField()
    base_value=models.DecimalField(max_digits=10, decimal_places=2, blank=True)
    expected_value=models.DecimalField(max_digits=10, decimal_places=2, blank=True)

    @property
    def package(self):
        try:
            return Package.objects.filter(patient=self.patient).order_by('-id').first()
        except Package.DoesNotExist:
            return None

    def calculate_approved_discount(self):
        if(self.package):
            if self.package.patient_type=='CASH':
                self.approved_package = self.package.total_package - self.discount
        else:
            pass

    def calculate_base_value(self):
        if (self.package):
            process_charge=self.package.total_package*15/100
            net_total_package=self.package.total_package - process_charge
            amount_per_fraction=net_total_package/self.package.max_fractions
            net_cost=amount_per_fraction*self.done_fractions
            gross_cost=net_cost+process_charge
            self.base_value=gross_cost
        else:
            self.base_value=self.approved_package

    def calculate_expected_value(self): #Edited
    if not self.expected_value < 0:
        if (self.package):
            if self.base_value<self.approved_package:
                self.expected_value=self.base_value
            else:
                self.expected_value=self.approved_package
        else:
            self.expected_value=0
    else:
        return abs(self.expected_value)

    def save(self, *args, **kwargs):
        self.calculate_approved_discount()
        self.calculate_base_value()
        self.calculate_expected_value()
        super(Receivables, self).save(*args, **kwargs)

class Realization(models.Model):
    patient=models.ForeignKey(Patient, on_delete=CASCADE)
    cash=models.BooleanField(default=False)
    amount_received=models.DecimalField(max_digits=10, decimal_places=2, default=0)
    billing_month=models.DateField(default=None)
    deficit_or_surplus_amount=models.DecimalField(max_digits=8, decimal_places=2, blank=True)
    deficit_percentage=models.FloatField(blank=True, default=0)
    surplus_percentage=models.FloatField(blank=True, default=0)
    remarks=models.TextField(max_length=500, default="N/A")

    @property
    def receivables(self):
        try:
            return Receivables.objects.filter(patient=self.patient).order_by('-id').first()
        except Receivables.DoesNotExist:
            return None

    @property
    def discharge(self):
        try:
            return Discharge.objects.filter(patient=self.patient).order_by('-id').first()
        except Discharge.DoesNotExist:
            return None

    @property
    def package(self):
        try:
            return Package.objects.filter(patient=self.patient).order_by('-id').first()
        except Package.DoesNotExist:
            return None


    def calculate_deficit_surplus_amount(self):
        if (self.receivables):
            print(self.receivables)
            self.deficit_or_surplus_amount=self.amount_received-self.receivables.expected_value
        else:
            self.deficit_or_surplus_amount=0

    def calculate_deficit_or_surplus_percentage(self):
        if (self.receivables):
            if self.amount_received>self.receivables.expected_value:
                self.surplus_percentage=self.deficit_or_surplus_amount/self.receivables.expected_value*100
                self.deficit_percentage=0
            elif self.amount_received<self.receivables.expected_value:
                self.deficit_percentage=self.deficit_or_surplus_amount/self.receivables.expected_value*100
                self.surplus_percentage=0
            elif self.amount_received==self.receivables.expected_value:
                self.deficit_percentage=0
                self.surplus_percentage=0
        else:
            self.surplus_percentage=0
            self.deficit_percentage=0

    def save(self, *args, **kwargs):
        self.calculate_deficit_surplus_amount()
        self.calculate_deficit_or_surplus_percentage()
        super(Realization, self).save(*args, **kwargs)

EDIT:

Now what I want is when a patient is paying the amount and if there is deficit (which is contained by deficit_or_surplus_amount), I want that deficit amount to be saved in the expected_value of Receivables, so that when we reclaim the amount, the further calculations would be based on that expected_value, when we do receive the deficit amount.

I don’t want to delete the previous instances but rather create a new instance of Receivables that has a new expected_value which now carries what was paid less the last time. So we expect that amount from the patient. So when the patient pays the next time, the deficit or surplus would be calculated on the basis of what was expected of him to pay this time.

For example:

If a patient gets admitted and has a Government scheme pay for him. Suppose the total expected_value is 75000 from him. He gets discharged and the we claim the amount to the Government. When we receive the amount, we get less amount, let’s say we received only 70000. So 5000 deficit. We reclaim the repudiated amount. Now we expect to receive 5000 from the Government, not 75000. So if we receive the amount from the scheme and it is not 5000, instead it’s only 2500, so the Realization table’s methods should be able to calculate the deficits or surpluses based on the now expected_value, i.e, 5000.

I hope my question is clear now. If you still want further explanation , please let me know.

I tried to use a signal for this purpose:

@receiver(post_save, sender=Realization)
def new_receivable_save(sender, instance, created, **kwargs):
    pkg=Package.objects.filter(patient=instance.patient).order_by('-id').first()
    rec=Receivables.objects.filter(patient=instance.patient).order_by('-id').first()
    if created:
        if pkg.patient_type!='CASH':
            if instance.deficit_or_surplus_amount<0:
                Receivables(
                    patient=rec.patient, 
                    rt_number=rec.rt_number, 
                    discount=rec.discount, 
                    approved_package=rec.approved_package, 
                    proposed_fractions=rec.proposed_fractions, 
                    done_fractions=rec.done_fractions, 
                    base_value=rec.base_value, 
                    expected_value=abs(instance.deficit_or_surplus_amount)
                ).save()

This function does create a new instance of Receivables but with the previous expected_value and not the recalculated one.

Where am I going wrong? How should I go about that? Thanks in advance.

Solution

You are saving the deficit amount correctly every time.

But you are not saving/updating the expected_value at all.

The first time you are saving the expected_value from base_value which is correct.

The next time amount received you have to update the expected_value (It has to be 5000, 2500).

  • 75000 base_value, 75000 expected_value.
  • 70000 amount_received – 5000 deficit – 5000 expected_value.
  • 2500 amount_received – 2500 deficit – 2500 expected_value.
  • 1300 amount_received – 1200 deficit – 1200 expected_value.

Here you are doing amount_received – previous expected_value (70000 – 75000 = -5000). You are doing in a negative/reverse way. Thats fine.

But Receivables model has save() which contains calculate_expected_value

    def calculate_expected_value(self):
        if (self.package):
            if self.base_value<self.approved_package:
                self.expected_value=self.base_value
            else:
                self.expected_value=self.approved_package
        else:
            self.expected_value=0

This method is overriding the expected_value in this model. It is not taking the passing expected value while initializing the Receivables(....).save() object.

Try modify above method like this:

def calculate_expected_value(self):
    if not self.expected_value < 0: # try something here, if expected value exists already while saving, we don't reassign it below.        
        if (self.package):
            if self.base_value<self.approved_package:
                self.expected_value=self.base_value
            else:
                self.expected_value=self.approved_package
        else:
            self.expected_value=0

This is where you might be going wrong. Please correct me if I am wrong.

EDIT:

def calculate_expected_value(self): #Edited
    if not self.expected_value < 0:
        if (self.package):
            if self.base_value<self.approved_package:
                self.expected_value=self.base_value
            else:
                self.expected_value=self.approved_package
        else:
            self.expected_value=0
    else:
        exp_value = self.expected_value * -1
        return exp_value
         

Answered By – Siva Sankar

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave A Reply

Your email address will not be published.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More