Money withdraw System got IntegrityError in OnetoOneField. All Works ok for first time then gets error

Viewed 45

Three tables in my model.py - Account, withdraw, taxDetails. I have a filed total amount (total_amnt_WoP) in the account table. Scenario is,  when I will try to withdraw an amount, it will reduce the total amount and also reduce some tax from it (10% of withdraw amount) and it will be saved in taxDetails table every time. I was trying to store total tax in the table.

In my case, it works fine (save the tax in taxDetails table) for the first time withdraw. But when I was trying to withdraw in second time, it gets:

IntegrityError.(IntegrityError at /account_balance/withdraw/, UNIQUE constraint failed: account_balance_taxdetails.user_id)

When I delete all the objects from withdraw table (withdraw.objects.all().delete()) or taxDetails (taxDetails.objects.all().delete()) table it works fine, but only for the first time. So what can be the solution?

Here is my models.py file:

class Account(models.Model):
    purchase_amnt=models.FloatField()
    ref_amnt=models.FloatField()
    prantic_amnt=models.FloatField()
    middle_amnt=models.FloatField()
    ehp_amnt=models.FloatField()
    esp_amnt=models.FloatField()
    incentive_amnt=models.FloatField()
    user=models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
    total_amnt_WoP= models.FloatField()


class withdraw(models.Model):
    account=models.ForeignKey(Account, on_delete=models.CASCADE)
    user=models.OneToOneField(User, blank=True, null=True, on_delete=models.CASCADE)

    prev_amnt=models.FloatField(blank=True, null=True, default=0)
    current_amnt=models.FloatField(blank=True, null=True, default=0)
    adjast_amnt=models.FloatField(blank=True, null=True, default=0)
    requisation_amnt=models.FloatField(blank=True, null=True, default=0)


    total_cashout_amnt=models.FloatField(default=0)
    transaction_id=models.CharField(max_length=100,blank=True, null=True)
    status=models.BooleanField(default=False)

    #purchase percentage
    prev_pur_tot=models.FloatField(blank=True, null=True, default=0)
    cashout_pur_tot=models.FloatField(default=0)
    current_pur_tot=models.FloatField(blank=True, null=True, default=0)
    created_at=models.DateTimeField(auto_now_add=True)
    modified_at=models.DateTimeField(auto_now=True)


class taxDetails(models.Model):
    withdra=models.ForeignKey(withdraw, on_delete=models.CASCADE, null=True)
    user=models.OneToOneField(User, null=True, on_delete=models.CASCADE)

    tax_prev=models.FloatField(default=0)
    tax_curr=models.FloatField(default=0)
    tax_amount_tot=models.FloatField(default=0)

    tax_id=models.CharField(max_length=100)
    tax_pay_date=models.DateTimeField(auto_now=True)
    tax_info_law=models.CharField(max_length=155, blank=True, null=True)
    tax_given_area=models.CharField(max_length=100,blank=True, null=True)
    tax_medium=models.CharField(max_length=100, blank=True, null=True)
    tax_description=models.CharField(max_length=100, blank=True, null=True)

views.py file:

from django.contrib import messages
from .models import Account, withdraw, tax, taxDetails
import datetime
from django.utils import timezone
from .forms import withdrawForm
from django.contrib.auth.models import User



#calculating total amount
def accountBalanceCalculation(request):
    acc=Account.objects.all()

    for i in acc:
        obj=Account.objects.get(id=i.id)
        pur=i.purchase_amnt
        ref=i.ref_amnt
        prantic=i.prantic_amnt
        middle=i.middle_amnt
        ehp=i.ehp_amnt
        esp=i.esp_amnt
        incentive=i.incentive_amnt
        totalamnts=(incentive+esp+ehp+middle+prantic+ref+pur)

        obj.total_amnt_WoP=totalamnts
        obj.save()

        # Taking additional values from account table to withdraw table
        obj2=withdraw()
        obj2.account=obj
        obj2.user= i.user
        obj2.prev_amnt= totalamnts
        obj2.current_amnt= totalamnts
        obj2.prev_pur_tot = pur
        obj2.save()

    return render(request,'account_balance/show.html')


def withdrawView(request):
    tt=Account.objects.filter().values_list('total_amnt_WoP')
    ttt=tt[0]

    if request.method == "POST":
        form=withdrawForm(request.POST)
        if form.is_valid():
            requisation_amnt=form.cleaned_data['requisation_amnt'] # withdraw amount
            print('---------------------requisation_amnt to withdraw --------------')
            print(requisation_amnt)

            obj=withdraw.objects.filter(user__id=request.user.id).first()

            # purchase percenetage calculated for 10%
            purchase_percentage=(obj.prev_pur_tot/obj.prev_amnt)*100
            print("purchase_percentage checkup for 10%")
            print(purchase_percentage)

            if purchase_percentage>=10 and obj.prev_amnt>=1: #check the conditions for withdraw
                transaction_id='1kfTxx56jlj' #Static input from admin

                obj.transaction_id = transaction_id
                obj.requisation_amnt=requisation_amnt

                temp_amt = obj.total_cashout_amnt + requisation_amnt 
                obj.total_cashout_amnt= temp_amt
                obj.current_amnt= obj.prev_amnt - temp_amt
                

                #Cutting the tax 10 %
                tax_percentage_amnt=(10/100)* requisation_amnt
                after_tax_bal=requisation_amnt- tax_percentage_amnt
                print("------------ after_tax_The_balance_is -------------:")
                print(after_tax_bal)

    
                abc=User.objects.get(id=request.user.id)
                obj3=taxDetails()
                obj3.user=abc
                obj3.withdra=obj
                obj3.tax_prev= tax_percentage_amnt
                obj3.tax_curr= tax_percentage_amnt
                obj3.tax_amount_tot= obj3.tax_amount_tot + tax_percentage_amnt
                obj3.save() # This line cases the error, every time...



                x = obj.prev_pur_tot
                pur_per_amnt= (10/100)* x

                print("-------------- purchase amnt in 10 percent scale--------")
                print(pur_per_amnt)


                y = obj.cashout_pur_tot + pur_per_amnt
                obj.cashout_pur_tot =  y
                obj.current_pur_tot= x - y
                obj.save()
                # obj.modified_at=timezone.now()
                messages.success(request, 'Your request is accepted!')
                return redirect('/account_balance/withdraw/')

        else:
            print("error")

    else:
        form=withdrawForm()
    
    context={
        'form': form,
        'ttt': ttt,
    }

    return render(request,'account_balance/withdraw.html', context)

form.py file:

from .models import Account, withdraw

class withdrawForm(forms.ModelForm):
    class Meta:
        model = withdraw
        fields = ['requisation_amnt']

Template:

{% extends 'basic.html' %}
{% load crispy_forms_tags %}
{% block body %}

<div class="card mt-5">
    <div class="card-body">
        <div class="col-md-6 offset-md-3">
            <form action="" method="post">
                {% csrf_token %}
                {{form|crispy}}
                
                <button type="submit" class="btn btn-primary">withdraw</button>
            </form>
        </div>

    </div>
</div>

{% endblock body %}

url.py file:

from .views import accountBalanceCalculation, withdrawView

app_name='account_balance'

urlpatterns = [
    path('accntbal/', accountBalanceCalculation, name="accntbal"),
    path('withdraw/', withdrawView, name="withdraw"),
]

# http://127.0.0.1:8000/account_balance/accntbal/
# http://127.0.0.1:8000/account_balance/withdraw/
1 Answers

The problem is in your code is when you add record for the first time it saves in your database but next when you add new record for same user with same id it gives error for UNIQUE constraint failed: you must update it instead of adding it.

for example you have to check before adding a record against same user or new user

try:
  if User.objects.get(id=request.user.id).exists():
     update data...
  else:
     create new record..
except Exception as e:
  print('Error : ',e)
Related