Django_Basic_Manufacturing/purchase/models.py
2025-08-19 12:28:49 +07:00

149 lines
5.2 KiB
Python

from django.db import models
from django.core.validators import MinValueValidator
from django.utils.translation import gettext_lazy as _
from decimal import Decimal
from inventory.models import Supplier
# Supplier model removed - using inventory.models.Supplier instead
class PurchaseOrder(models.Model):
"""Purchase order model"""
ORDER_STATUS = [
('draft', 'Draft'),
('sent', 'Sent to Supplier'),
('confirmed', 'Confirmed by Supplier'),
('received', 'Received'),
('cancelled', 'Cancelled'),
]
order_number = models.CharField(max_length=50, unique=True, help_text='Unique purchase order number')
supplier = models.ForeignKey('inventory.Supplier', on_delete=models.CASCADE, related_name='purchase_orders')
date = models.DateField()
expected_delivery_date = models.DateField(blank=True, null=True)
status = models.CharField(max_length=20, choices=ORDER_STATUS, default='draft')
# Financial information
subtotal = models.DecimalField(
max_digits=12,
decimal_places=2,
default=0,
validators=[MinValueValidator(Decimal('0'))]
)
tax_amount = models.DecimalField(
max_digits=12,
decimal_places=2,
default=0,
validators=[MinValueValidator(Decimal('0'))]
)
shipping_cost = models.DecimalField(
max_digits=12,
decimal_places=2,
default=0,
validators=[MinValueValidator(Decimal('0'))]
)
total_amount = models.DecimalField(
max_digits=12,
decimal_places=2,
default=0,
validators=[MinValueValidator(Decimal('0'))]
)
# Additional information
notes = models.TextField(blank=True)
terms_conditions = models.TextField(blank=True)
# User tracking
created_by = models.ForeignKey('users.CustomUser', on_delete=models.SET_NULL, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-date', '-created_at']
verbose_name = _('Purchase Order')
verbose_name_plural = _('Purchase Orders')
def __str__(self):
return f"PO-{self.order_number} - {self.supplier.name}"
def save(self, *args, **kwargs):
"""Override save to calculate total amount"""
self.total_amount = self.subtotal + self.tax_amount + self.shipping_cost
super().save(*args, **kwargs)
def get_item_count(self):
"""Get total number of items in this purchase order"""
return self.items.count()
def is_overdue(self):
"""Check if delivery is overdue"""
if self.expected_delivery_date and self.status not in ['received', 'cancelled']:
from django.utils import timezone
return timezone.now().date() > self.expected_delivery_date
return False
class PurchaseOrderItem(models.Model):
"""Individual items in purchase orders"""
purchase_order = models.ForeignKey(PurchaseOrder, on_delete=models.CASCADE, related_name='items')
product = models.ForeignKey('inventory.Product', on_delete=models.CASCADE, related_name='purchase_order_items')
quantity = models.DecimalField(
max_digits=10,
decimal_places=2,
validators=[MinValueValidator(Decimal('0.01'))]
)
unit_price = models.DecimalField(
max_digits=10,
decimal_places=2,
validators=[MinValueValidator(Decimal('0'))]
)
total_price = models.DecimalField(
max_digits=12,
decimal_places=2,
validators=[MinValueValidator(Decimal('0'))]
)
# Additional information
description = models.CharField(max_length=200, blank=True)
notes = models.TextField(blank=True)
class Meta:
verbose_name = _('Purchase Order Item')
verbose_name_plural = _('Purchase Order Items')
def __str__(self):
return f"{self.purchase_order.order_number} - {self.product.name} ({self.quantity})"
def save(self, *args, **kwargs):
"""Override save to calculate total price"""
self.total_price = self.quantity * self.unit_price
super().save(*args, **kwargs)
# Update purchase order subtotal
self.purchase_order.subtotal = self.purchase_order.items.aggregate(
total=models.Sum('total_price')
)['total'] or Decimal('0')
self.purchase_order.save()
class PurchaseReceipt(models.Model):
"""Receipt for received purchase orders"""
receipt_number = models.CharField(max_length=50, unique=True)
purchase_order = models.ForeignKey(PurchaseOrder, on_delete=models.CASCADE, related_name='receipts')
receipt_date = models.DateField()
# Receipt details
notes = models.TextField(blank=True)
received_by = models.ForeignKey('users.CustomUser', on_delete=models.SET_NULL, null=True)
# Timestamps
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-receipt_date']
verbose_name = _('Purchase Receipt')
verbose_name_plural = _('Purchase Receipts')
def __str__(self):
return f"Receipt-{self.receipt_number} for PO-{self.purchase_order.order_number}"