+
+
+
+
+
{{ acceptance.trade_offer.initiated_by.user.email|gravatar:40 }}
-
Has
+
+ {% if acceptance.is_initiator_state %}
+ {{ acceptance.action_label_2 }}
+ {% else %}
+ Waiting on {{ acceptance.trade_offer.initiated_by.user.username }} to {{ acceptance.next_action_label }}...
+ {% endif %}
+
+
+
+
+
+
+
+
{% card_badge acceptance.requested_card %}
+
+
+
{% card_badge acceptance.offered_card %}
+
+
+
+
+
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/theme/templatetags/trade_offer.html b/theme/templatetags/trade_offer.html
index d620f8e..c20457d 100644
--- a/theme/templatetags/trade_offer.html
+++ b/theme/templatetags/trade_offer.html
@@ -27,12 +27,12 @@
{% if num_cards_available > 0 %}
{% for card in have_cards_available %}
-
{% card_badge card.card card.quantity %}
+
{% card_badge card.card card.quantity %}
{% endfor %}
{% for card in want_cards_available %}
-
{% card_badge card.card card.quantity %}
+
{% card_badge card.card card.quantity %}
{% endfor %}
{% else %}
diff --git a/trades/migrations/0001_initial.py b/trades/migrations/0001_initial.py
index e3193e5..55c0835 100644
--- a/trades/migrations/0001_initial.py
+++ b/trades/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.1.2 on 2025-04-08 06:24
+# Generated by Django 5.1.2 on 2025-04-13 05:10
import django.db.models.deletion
from django.db import migrations, models
@@ -52,6 +52,7 @@ class Migration(migrations.Migration):
('trade_offer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='trade_offer_have_cards', to='trades.tradeoffer')),
],
options={
+ 'ordering': ['card__name'],
'unique_together': {('trade_offer', 'card')},
},
),
@@ -70,6 +71,7 @@ class Migration(migrations.Migration):
('trade_offer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='trade_offer_want_cards', to='trades.tradeoffer')),
],
options={
+ 'ordering': ['card__name'],
'unique_together': {('trade_offer', 'card')},
},
),
diff --git a/trades/models.py b/trades/models.py
index ab5dafa..5ca0d84 100644
--- a/trades/models.py
+++ b/trades/models.py
@@ -100,7 +100,6 @@ class TradeOffer(models.Model):
# Use super().save() here to avoid recursion.
super(TradeOffer, self).save(update_fields=["rarity_level", "rarity_icon"])
- # New derived properties for available cards
@property
def have_cards_available(self):
# Returns the list of have_cards (through objects) that still have available quantity.
@@ -136,6 +135,10 @@ class TradeOfferHaveCard(models.Model):
quantity = models.PositiveIntegerField(default=1)
qty_accepted = models.PositiveIntegerField(default=0, editable=False)
+ @property
+ def qty_available(self):
+ return self.quantity - self.qty_accepted
+
def __str__(self):
return f"{self.card.name} x{self.quantity} (Accepted: {self.qty_accepted})"
@@ -166,6 +169,10 @@ class TradeOfferWantCard(models.Model):
quantity = models.PositiveIntegerField(default=1)
qty_accepted = models.PositiveIntegerField(default=0, editable=False)
+ @property
+ def qty_available(self):
+ return self.quantity - self.qty_accepted
+
def __str__(self):
return f"{self.card.name} x{self.quantity} (Accepted: {self.qty_accepted})"
@@ -246,6 +253,17 @@ class TradeAcceptance(models.Model):
AcceptanceState.THANKED_BY_BOTH: "Send Thanks",
}
+ ALTERNATE_ACTION_LABELS_2 = {
+ AcceptanceState.REJECTED_BY_INITIATOR: "Rejected this Trade",
+ AcceptanceState.REJECTED_BY_ACCEPTOR: "Rejected this Trade",
+ AcceptanceState.ACCEPTED: "Accepted this Trade",
+ AcceptanceState.SENT: "Sent the Card",
+ AcceptanceState.RECEIVED: "Received the Card and Responded",
+ AcceptanceState.THANKED_BY_INITIATOR: "Sent Thanks",
+ AcceptanceState.THANKED_BY_ACCEPTOR: "Sent Thanks",
+ AcceptanceState.THANKED_BY_BOTH: "Sent Thanks",
+ }
+
@classmethod
def get_action_label_for_state(cls, state_value):
"""
@@ -262,6 +280,46 @@ class TradeAcceptance(models.Model):
"""
return self.get_action_label_for_state(self.state)
+ @property
+ def next_action_label(self):
+ """
+ Returns what the next action label would be based on the current state.
+ """
+ if self.state == self.AcceptanceState.ACCEPTED:
+ return self.get_action_label_for_state(self.AcceptanceState.SENT)
+ elif self.state == self.AcceptanceState.SENT:
+ return self.get_action_label_for_state(self.AcceptanceState.RECEIVED)
+ elif self.state == self.AcceptanceState.RECEIVED or self.state == self.AcceptanceState.THANKED_BY_ACCEPTOR or self.state == self.AcceptanceState.THANKED_BY_INITIATOR:
+ return self.get_action_label_for_state(self.AcceptanceState.THANKED_BY_BOTH)
+ else:
+ return None
+
+
+ @classmethod
+ def get_action_label_for_state_2(cls, state_value):
+ """
+ Returns the alternate action label for the provided state_value.
+ If no alternate label exists, falls back to the default label.
+ """
+ default = dict(cls.AcceptanceState.choices).get(state_value, state_value)
+ return cls.ALTERNATE_ACTION_LABELS_2.get(state_value, default)
+
+ @property
+ def action_label_2(self):
+ """
+ For the current acceptance state, return the alternate action label.
+ """
+ return self.get_action_label_for_state_2(self.state)
+
+ @property
+ def is_initiator_state(self):
+ return self.state in [self.AcceptanceState.SENT.value, self.AcceptanceState.THANKED_BY_INITIATOR.value, self.AcceptanceState.THANKED_BY_BOTH.value]
+
+ @property
+ def is_acceptor_state(self):
+ return self.state in [self.AcceptanceState.ACCEPTED.value, self.AcceptanceState.RECEIVED.value, self.AcceptanceState.THANKED_BY_ACCEPTOR.value, self.AcceptanceState.THANKED_BY_BOTH.value]
+
+
@property
def is_completed(self):
return self.state in {
diff --git a/trades/templatetags/trade_offer_tags.py b/trades/templatetags/trade_offer_tags.py
index 1848f58..c3b4eb9 100644
--- a/trades/templatetags/trade_offer_tags.py
+++ b/trades/templatetags/trade_offer_tags.py
@@ -1,5 +1,6 @@
from django import template
from math import ceil
+from trades.models import TradeAcceptance
register = template.Library()
@register.inclusion_tag('templatetags/trade_offer.html', takes_context=True)
@@ -20,9 +21,7 @@ def render_trade_offer(context, offer):
if card.quantity > card.qty_accepted
]
- acceptances = [acceptance for acceptance in list(offer.acceptances.all())
- if acceptance.is_active
- ]
+ acceptances = list(offer.acceptances.all())
# Determine if the offer should show its back side (acceptances view) by default.
# If either side has no available cards, then flip the offer.
@@ -51,6 +50,7 @@ def render_trade_acceptance(context, acceptance):
"""
Renders a simple trade acceptance view with a single row and simplified header/footer.
"""
+
return {
"acceptance": acceptance,
"request": context.get("request"),