Last active
November 29, 2024 09:24
-
-
Save siumhossain/209a189bd8a78a957d5c54dca6611935 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from django.db import models | |
| from django.core.validators import MinValueValidator | |
| from decimal import Decimal | |
| from django.utils import timezone | |
| from django.db.models import Sum | |
| class PaymentMethod(models.Model): | |
| name = models.CharField(max_length=50) | |
| is_active = models.BooleanField(default=True) | |
| def __str__(self): | |
| return self.name | |
| class Order(models.Model): | |
| order_number = models.CharField(max_length=50, unique=True) | |
| date = models.DateTimeField(default=timezone.now) | |
| total_amount = models.DecimalField(max_digits=10, decimal_places=2) | |
| notes = models.TextField(blank=True) | |
| def __str__(self): | |
| return f"Order {self.order_number}" | |
| class Purchase(models.Model): | |
| STATUS_CHOICES = [ | |
| ('pending', 'Pending'), | |
| ('partial', 'Partially Paid'), | |
| ('completed', 'Completed'), | |
| ] | |
| order = models.ForeignKey(Order, on_delete=models.PROTECT) | |
| date = models.DateTimeField(default=timezone.now) | |
| total_amount = models.DecimalField(max_digits=10, decimal_places=2) | |
| paid_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0) | |
| status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') | |
| notes = models.TextField(blank=True) | |
| def get_remaining_balance(self): | |
| return self.total_amount - self.paid_amount | |
| def get_payment_history(self): | |
| return self.payments.all().order_by('-date') | |
| def get_payment_summary(self): | |
| summary = self.payments.values('payment_method__name').annotate( | |
| total=Sum('amount') | |
| ).order_by('payment_method__name') | |
| return summary | |
| def save(self, *args, **kwargs): | |
| if self.paid_amount >= self.total_amount: | |
| self.status = 'completed' | |
| elif self.paid_amount > 0: | |
| self.status = 'partial' | |
| else: | |
| self.status = 'pending' | |
| super().save(*args, **kwargs) | |
| def __str__(self): | |
| return f"Purchase for Order {self.order.order_number} - {self.status} (Balance: {self.get_remaining_balance()})" | |
| class PurchasePayment(models.Model): | |
| purchase = models.ForeignKey(Purchase, on_delete=models.PROTECT, related_name='payments') | |
| payment_method = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT) | |
| amount = models.DecimalField(max_digits=10, decimal_places=2) | |
| date = models.DateTimeField(default=timezone.now) | |
| reference_number = models.CharField(max_length=50, blank=True) | |
| notes = models.TextField(blank=True) | |
| def save(self, *args, **kwargs): | |
| super().save(*args, **kwargs) | |
| # Update purchase paid amount | |
| total_paid = self.purchase.payments.aggregate( | |
| total=Sum('amount'))['total'] or 0 | |
| self.purchase.paid_amount = total_paid | |
| self.purchase.save() | |
| def __str__(self): | |
| return f"Payment of {self.amount} for Purchase {self.purchase.order.order_number}" | |
| class Sale(models.Model): | |
| STATUS_CHOICES = [ | |
| ('pending', 'Pending'), | |
| ('partial', 'Partially Paid'), | |
| ('completed', 'Completed'), | |
| ] | |
| order = models.ForeignKey(Order, on_delete=models.PROTECT) | |
| date = models.DateTimeField(default=timezone.now) | |
| total_amount = models.DecimalField(max_digits=10, decimal_places=2) | |
| received_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0) | |
| status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') | |
| notes = models.TextField(blank=True) | |
| def get_remaining_balance(self): | |
| return self.total_amount - self.received_amount | |
| def get_payment_history(self): | |
| return self.payments.all().order_by('-date') | |
| def get_payment_summary(self): | |
| summary = self.payments.values('payment_method__name').annotate( | |
| total=Sum('amount') | |
| ).order_by('payment_method__name') | |
| return summary | |
| def save(self, *args, **kwargs): | |
| if self.received_amount >= self.total_amount: | |
| self.status = 'completed' | |
| elif self.received_amount > 0: | |
| self.status = 'partial' | |
| else: | |
| self.status = 'pending' | |
| super().save(*args, **kwargs) | |
| def __str__(self): | |
| return f"Sale for Order {self.order.order_number} - {self.status} (Balance: {self.get_remaining_balance()})" | |
| class SalePayment(models.Model): | |
| sale = models.ForeignKey(Sale, on_delete=models.PROTECT, related_name='payments') | |
| payment_method = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT) | |
| amount = models.DecimalField(max_digits=10, decimal_places=2) | |
| date = models.DateTimeField(default=timezone.now) | |
| reference_number = models.CharField(max_length=50, blank=True) | |
| notes = models.TextField(blank=True) | |
| def save(self, *args, **kwargs): | |
| super().save(*args, **kwargs) | |
| # Update sale received amount | |
| total_received = self.sale.payments.aggregate( | |
| total=Sum('amount'))['total'] or 0 | |
| self.sale.received_amount = total_received | |
| self.sale.save() | |
| def __str__(self): | |
| return f"Payment of {self.amount} for Sale {self.sale.order.order_number}" | |
| class Expense(models.Model): | |
| CATEGORY_CHOICES = [ | |
| ('utilities', 'Utilities'), | |
| ('rent', 'Rent'), | |
| ('salary', 'Salary'), | |
| ('supplies', 'Supplies'), | |
| ('other', 'Other'), | |
| ] | |
| date = models.DateTimeField(default=timezone.now) | |
| category = models.CharField(max_length=20, choices=CATEGORY_CHOICES) | |
| amount = models.DecimalField(max_digits=10, decimal_places=2) | |
| payment_method = models.ForeignKey(PaymentMethod, on_delete=models.PROTECT) | |
| description = models.TextField() | |
| reference_number = models.CharField(max_length=50, blank=True) | |
| def __str__(self): | |
| return f"{self.category} - {self.amount}" | |
| class DailyBalance(models.Model): | |
| date = models.DateField(unique=True) | |
| opening_balance = models.DecimalField(max_digits=12, decimal_places=2) | |
| closing_balance = models.DecimalField(max_digits=12, decimal_places=2) | |
| total_sales = models.DecimalField(max_digits=12, decimal_places=2, default=0) | |
| total_purchases = models.DecimalField(max_digits=12, decimal_places=2, default=0) | |
| total_expenses = models.DecimalField(max_digits=12, decimal_places=2, default=0) | |
| class Meta: | |
| ordering = ['-date'] | |
| def calculate_closing_balance(self): | |
| self.closing_balance = ( | |
| self.opening_balance + | |
| self.total_sales - | |
| self.total_purchases - | |
| self.total_expenses | |
| ) | |
| return self.closing_balance | |
| def save(self, *args, **kwargs): | |
| # Calculate totals for the day | |
| today = self.date | |
| self.total_sales = SalePayment.objects.filter( | |
| date__date=today | |
| ).aggregate(total=Sum('amount'))['total'] or 0 | |
| self.total_purchases = PurchasePayment.objects.filter( | |
| date__date=today | |
| ).aggregate(total=Sum('amount'))['total'] or 0 | |
| self.total_expenses = Expense.objects.filter( | |
| date__date=today | |
| ).aggregate(total=Sum('amount'))['total'] or 0 | |
| self.calculate_closing_balance() | |
| super().save(*args, **kwargs) | |
| def __str__(self): | |
| return f"Balance for {self.date}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment