from django.db import models import hashlib # <-- import hashlib for computing md5 from cards.models import Card from friend_codes.models import FriendCode class TradeOffer(models.Model): id = models.AutoField(primary_key=True) hash = models.CharField(max_length=8, editable=False) initiated_by = models.ForeignKey("friend_codes.FriendCode", on_delete=models.PROTECT, related_name='initiated_by') accepted_by = models.ForeignKey("friend_codes.FriendCode", on_delete=models.PROTECT, null=True, blank=True, related_name='accepted_by') want_cards = models.ManyToManyField("cards.Card", related_name='trade_offers_want') have_cards = models.ManyToManyField("cards.Card", related_name='trade_offers_have') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class State(models.TextChoices): INITIATED = 'INITIATED', 'Initiated' ACCEPTED = 'ACCEPTED', 'Accepted' SENT = 'SENT', 'Sent' RECEIVED = 'RECEIVED', 'Received' state = models.CharField( max_length=10, choices=State.choices, default=State.INITIATED, ) def __str__(self): return f"Want: {', '.join([x.name for x in self.want_cards.all()])} -> Have: {', '.join([x.name for x in self.have_cards.all()])}" def update_state(self, new_state): """ Explicitly update the trade state to new_state if allowed. Allowed transitions: - INITIATED -> ACCEPTED - ACCEPTED -> SENT - SENT -> RECEIVED Raises: ValueError: If the new_state is not allowed. """ allowed_transitions = { self.State.INITIATED: self.State.ACCEPTED, self.State.ACCEPTED: self.State.SENT, self.State.SENT: self.State.RECEIVED } # Check that new_state is one of the defined State choices if new_state not in [choice[0] for choice in self.State.choices]: raise ValueError(f"'{new_state}' is not a valid state.") # If the current state is already final, no further transition is allowed. if self.state not in allowed_transitions: raise ValueError(f"No transitions allowed from the final state '{self.state}'.") # Verify that the desired new_state is the valid transition for the current state. if allowed_transitions[self.state] != new_state: raise ValueError(f"Transition from {self.state} to {new_state} is not allowed.") self.state = new_state # Save all changes so that any in-memory modifications (like accepted_by) are persisted. self.save() # Changed from self.save(update_fields=["state"]) def save(self, *args, **kwargs): # Determine if the object is being created (i.e. it doesn't yet have a pk) is_new = self.pk is None super().save(*args, **kwargs) # Once the object has a pk, compute and save the hash if it hasn't been set yet. if is_new and not self.hash: self.hash = hashlib.md5(str(self.id).encode('utf-8')).hexdigest()[:8] super().save(update_fields=["hash"])