Skip to content

Instantly share code, notes, and snippets.

@tecoholic
Created March 27, 2023 16:01
Show Gist options
  • Save tecoholic/bc113f7aaa1994953df13ccca879ffbe to your computer and use it in GitHub Desktop.
Save tecoholic/bc113f7aaa1994953df13ccca879ffbe to your computer and use it in GitHub Desktop.
"""
This entire file is from ChatGPT generated code.
Here are the list of prompts that led to this output:
1. Create a Django model to record bank transactions from a personal bank
account
2. add currency, foreign currency related fields to the model to handle
international transactions
3. Create an account model to hold the bank account information and update
the transaction model to include source and destination accounts
necessary for double book keeping method of records
"""
from django.db import models
from django.contrib.auth.models import User
class Account(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
account_number = models.CharField(max_length=50)
balance = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return f"{self.user.username} - {self.name} ({self.account_number})"
class BankTransaction(models.Model):
TRANSACTION_TYPES = (
("deposit", "Deposit"),
("withdrawal", "Withdrawal"),
("transfer", "Transfer"),
)
user = models.ForeignKey(User, on_delete=models.CASCADE)
transaction_date = models.DateTimeField()
description = models.CharField(max_length=100)
transaction_type = models.CharField(max_length=50, choices=TRANSACTION_TYPES)
amount = models.DecimalField(max_digits=10, decimal_places=2)
currency = models.CharField(max_length=3, default="USD")
exchange_rate = models.DecimalField(
max_digits=10, decimal_places=4, null=True, blank=True
)
foreign_amount = models.DecimalField(
max_digits=10, decimal_places=2, null=True, blank=True
)
source_account = models.ForeignKey(
Account,
on_delete=models.CASCADE,
related_name="source_transactions",
null=True,
blank=True,
)
destination_account = models.ForeignKey(
Account,
on_delete=models.CASCADE,
related_name="destination_transactions",
null=True,
blank=True,
)
balance = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return f"{self.user.username} - {self.description}"
def save(self, *args, **kwargs):
if self.transaction_type == "transfer":
if not self.source_account or not self.destination_account:
raise ValueError(
"Source and destination accounts are required for transfers"
)
if self.source_account == self.destination_account:
raise ValueError("Source and destination accounts cannot be the same")
if self.currency != "USD" and not self.exchange_rate:
raise ValueError(
"Exchange rate is required for foreign currency transfers"
)
if self.currency == "USD" and self.foreign_amount:
raise ValueError("Foreign amount should be empty for USD transfers")
if self.exchange_rate and not self.foreign_amount:
raise ValueError(
"Foreign amount is required for foreign currency transfers"
)
if self.exchange_rate and self.foreign_amount:
self.amount = self.foreign_amount * self.exchange_rate
self.source_account.balance -= self.amount
self.destination_account.balance += self.amount
self.source_account.save()
self.destination_account.save()
elif self.transaction_type == "deposit":
if not self.destination_account:
raise ValueError("Destination account is required for deposits")
if self.currency != "USD" and not self.exchange_rate:
raise ValueError(
"Exchange rate is required for foreign currency deposits"
)
if self.currency == "USD" and self.foreign_amount:
raise ValueError("Foreign amount should be empty for USD deposits")
if self.exchange_rate and not self.foreign_amount:
raise ValueError(
"Foreign amount is required for foreign currency deposits"
)
if self.exchange_rate and self.foreign_amount:
self.amount = self.foreign_amount * self.exchange_rate
self.destination_account.balance += self.amount
self.destination_account.save()
elif self.transaction_type == "withdrawal":
if not self.source_account:
raise ValueError("Source account is required for withdrawals")
if self.currency != "USD" and not self.exchange_rate:
raise ValueError(
"Exchange rate is required for foreign currency withdrawals"
)
if self.currency == "USD" and self.foreign_amount:
raise ValueError("Foreign amount should be empty for USD withdrawals")
if self.exchange_rate and not self.foreign_amount:
raise ValueError(
"Foreign amount is required for foreign currency withdrawals"
)
if self.exchange_rate and self.foreign_amount:
self.amount = self.foreign_amount * self.exchange_rate
self.source_account.balance -= self.amount
self.source_account.save()
# Update balance for source and destination accounts (if applicable)
if self.source_account:
self.balance = self.source_account.balance
elif self.destination_account:
self.balance = self.destination_account.balance
super().save(*args, **kwargs)
@tecoholic
Copy link
Author

Q: Why is the balance field necessary? Can't we just calculate it on the fly?

ChatGPT:
You are correct that the balance field is not strictly necessary and it can be calculated on the fly based on the transactions in the account. However, storing the balance as a field in the BankTransaction model can have some advantages, such as:

  1. Performance: Calculating the balance on the fly requires querying all transactions in the account and calculating the running total. This can be resource-intensive and slow down the application, especially as the number of transactions grows. Storing the balance as a field can make it easier to retrieve and display the balance for a given transaction, without the need for additional calculations.
  2. Consistency: Storing the balance as a field ensures that the balance for each transaction is consistent and accurate at the time of the transaction. If the balance is calculated on the fly, there is a risk that the balance calculation might change as new transactions are added or edited, potentially leading to inconsistencies or errors in the balance calculation.
  3. Flexibility: Storing the balance as a field allows you to store different types of balances, such as the current balance, available balance, or future balance. Calculating these different balances on the fly can be more complex and may require additional queries or calculations.

That being said, if you have a small number of transactions and performance is not a concern, it may be fine to calculate the balance on the fly. Ultimately, the decision of whether to store the balance as a field depends on your specific requirements and trade-offs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment