Search code examples
pythondjangodjango-viewsdjango-channelsbanking

Implementing Name Synchronization and Money Transfers in Transactions Model with Account Number Input


I have the following models in my Django application:

class Transaction (models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    account_number = models.IntegerField()
    name = models.CharField(max_length=50)
    amount = models.DecimalField(max_digits=5, decimal_places=2)
    created_on = models.DateTimeField()

class Wallet(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    account_balance = models.DecimalField(max_digits=5, decimal_places=2, default=0)

class AccountNum(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    account_number = models.IntegerField()
    slug = models.SlugField(unique=True)

I want to implement a feature where the name field in the Transactions model gets synchronized with the account owner's name based on the provided account_number input. Additionally, I want to enable money transfers using the current user's wallet and the specified amount in the Transactions model.

To provide some context, I have a post-save signal generate_account_number which generates a random 10-digit account number.

What are some recommended techniques or approaches to achieve this synchronization of the name field with the account owner's name and enable money transfers using the wallet model and specified amount in the Transaction model?


Solution

  • Even though I failed to implement an account name based on a given account number, I'm happy to share the way we can send money from one account to another.

    The technical way to do so is by creating only two models, Account and Transaction models, and adding what is in the Wallet model to an Account model like this:

    class Account(models.Model):
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        account_number = models.IntegerField()
        account_balance = models.DecimalField(max_digits=12, decimal_places=6)
    

    To send fund from one account to another, we have to create sender and receiver field and assign them to a CustomUser model with different related_name in the Transaction model, just like this:

    import random
    
    def generate_random_number():
        return random.randint(1, 30)
    
    class Transaction(models.Model):
        amount = models.DecimalField(max_digits=12, decimal_places=6)
        sender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='transfer_sents')
        receiver = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='transfer_receives')
        account_number = models.IntegerField()
        name = models.CharField(max_length=50)
        refrence_number = models.CharField(max_length=50, default=generate_random_number)
    

    I've written a Django view function that's designed to handle financial transactions. Let me break down how it works:

    The view takes the amount and name values from the submitted form data, and it retrieves the sender and receiver account objects from the database using the Account model. The sender account is associated with the currently logged-in user, while the receiver account is identified by the account_number provided in the form data, and then ensure there are sufficient funds, the view checks if the sender account balance can cover the transaction amount. If it can, the view deducts the 'amount' from the sender account balance and increases the receiver account balance by the same 'amount'. These changes are then saved to the database. In the event of insufficient funds in the sender account, the view generates an error message using Django messaging framework. The user is then redirected to that page.

        views.py
    from decimal import Decimal
    from django.contrib import messages
    
    def create_transfer(request):
        if request.method == 'POST':
            
            amount = Decimal(request.POST.get('amount'))
            name = request.POST.get('name')
    
            sender_account = Account.objects.get(user=request.user)  
            receiver_account = Account.objects.get(account_number=request.POST.get('account_number'))
    
            if sender_account.account_balance >= amount:
                sender_account.account_balance -= amount
                sender_account.save()
    
                receiver_account.account_balance += amount
                receiver_account.save()
    
                Transaction.objects.create(
                    sender=sender_account.user, 
                    receiver=receiver_account.user,
                    amount=amount, 
                    name=name, 
                    account_number=receiver_account
                )
            else:
                messages.error(request, 'Insufficient Funds')
                return redirect('Transaction')
        return render(request, 'create_transfer.html')