Add needs_price_update field to Purchase model #94

Merged
lukas merged 3 commits from purchase-needs-price-update into main 2026-05-12 13:03:34 +00:00
6 changed files with 359 additions and 66 deletions
+157
View File
@@ -0,0 +1,157 @@
# Game & Purchase Status Definitions
## Game Statuses
Games have a `status` field with the following values:
| Status | Code | Description |
|--------|------|-------------|
| **Unplayed** | `u` | Game was purchased but never played |
| **Played** | `p` | Game was played but not yet finished |
| **Finished** | `f` | Game has been completed |
| **Retired** | `r` | Game was intentionally retired (e.g., no longer accessible, collector's item) |
| **Abandoned** | `a` | Game was played but the user gave up on it |
**Setting game status:**
- Users explicitly set game status via the UI (finish/drop purchase buttons, status change form)
- Status changes are tracked in `GameStatusChange` model
- Refunding a purchase always marks its games as abandoned
---
## Purchase-Level Status Concepts
These concepts determine whether a purchase appears in the "unfinished" or "dropped" lists in stats views.
### Finished
A purchase is considered **finished** when:
```
Game.status == "f" OR Purchase.games.* has a PlayEvent with an ended date
```
Either signal indicates the game is complete:
- **Explicit**: User marked the game as finished (`Game.status = "f"`)
- **Implicit**: A PlayEvent exists with `ended` date set (data-driven)
This uses **OR** logic during a transition period. Later, these signals should be kept in sync so only one source of truth is needed.
### Dropped
A purchase is considered **dropped** when:
```
Game.status == "a" OR Purchase.date_refunded IS NOT NULL
```
Either signal indicates the user no longer has an active interest in the game:
- **Explicit**: User marked the game as abandoned (`Game.status = "a"`)
- **Implicit**: User refunded the purchase (which automatically sets games to abandoned)
Note: Refunding a purchase always marks its games as abandoned. There is no option to refund without abandoning.
---
## Unfinished vs. Dropped
The stats views categorize purchases into **unfinished** and **dropped** lists.
### Unfinished
A purchase is **unfinished** when:
1. It was purchased in the relevant time period (this year for yearly stats, all time for all-time stats)
2. It was NOT refunded (only counts toward unfinished/backlog)
3. It is NOT finished (per the finished definition above)
4. It is NOT dropped (per the dropped definition above)
5. It is NOT infinite (subscription, etc.)
6. It IS a game or DLC (not season passes or battle passes)
**Unfinished = Active backlog** — games the user may still play.
### Dropped
A purchase is **dropped** when:
1. It was purchased in the relevant time period
2. It is NOT finished (per the finished definition above)
3. It matches at least one dropped signal (per the dropped definition above)
4. It is NOT infinite
5. It IS a game or DLC
**Dropped = Terminal state** — games the user has given up on or refunded.
### Summary Table
| Category | Includes Refunded? | Key Condition |
|----------|-------------------|---------------|
| **Unfinished** | No | NOT finished, NOT dropped |
| **Dropped** | Yes | Finished OR Abandoned/Retired |
| **Refunded** | Yes | `date_refunded IS NOT NULL` |
| **Infinite** | Yes | `infinite = True` |
---
## Query Patterns
### Checking if a game is finished
```python
game.finished() # Returns True if status="f" or has PlayEvent with ended date
```
### Checking if a game is abandoned
```python
game.abandoned() # Returns True if status="a"
```
### Getting finished purchases
```python
Purchase.objects.finished() # All purchases where games are finished
```
### Getting dropped purchases
```python
Purchase.objects.dropped() # All purchases that are abandoned or refunded
```
---
## Transition State
The system uses **OR logic** for both finished and dropped to catch any mismatch between explicit user actions and data signals:
- **Finished**: `status="f" OR PlayEvent.ended`
- **Dropped**: `status="a" OR date_refunded`
This bridges the gap between the old model (where `date_finished` and `date_dropped` were on the Purchase model) and the new model (where `Game.status` and `PlayEvent` are the sources of truth).
**Future:** These signals should be kept in sync. For example:
- Setting `Game.status = "f"` should create a PlayEvent with `ended` date
- When the sync is reliable, the OR can be simplified to a single check
Note: Refunding a purchase always automatically sets its games' status to Abandoned. This is not optional — there is no way to refund without abandoning.
---
## Edge Cases
### Unplayed games
- Unplayed games (`status="u"`) are considered **unfinished**, not dropped
- They appear in the unfinished/backlog list since they are still games the user may play
- Unplayed games that are refunded DO count as **dropped** (refund signal overrides)
### Multiple games per purchase
- A purchase can have multiple games via `Purchase.games` (many-to-many)
- A purchase is finished if ANY of its games is finished
- A purchase is dropped if ANY of its games is abandoned OR the purchase itself is refunded
### PlayEvents without ended date
- A PlayEvent with `started` but no `ended` does NOT count as finished
- This represents a game that was started but not completed
### Retired games
- Retired games (`status="r"`) are considered **dropped**
- Retirement is for games the user intentionally removed from their collection (collector's items, no longer accessible, etc.)
@@ -0,0 +1,22 @@
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
# Generated by Django 6.0.1 on 2026-05-12 11:57
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
from django.db import migrations, models
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
class Migration(migrations.Migration):
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
dependencies = [
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
('games', '0015_alter_purchase_date_purchased_and_more'),
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
]
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
operations = [
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
migrations.AddField(
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
model_name='purchase',
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
name='needs_price_update',
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
field=models.BooleanField(db_index=True, default=True),
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
),
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
migrations.RunSQL(
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
"UPDATE games_purchase SET needs_price_update = FALSE WHERE converted_price IS NOT NULL AND converted_currency != ''",
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
reverse_sql="UPDATE games_purchase SET needs_price_update = TRUE WHERE converted_price IS NOT NULL AND converted_currency != ''",
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
),
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
]
lukas marked this conversation as resolved
Review

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.

The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
+1 -19
View File
@@ -179,6 +179,7 @@ class Purchase(models.Model):
price_currency = models.CharField(max_length=3, default="USD") price_currency = models.CharField(max_length=3, default="USD")
converted_price = models.FloatField(null=True) converted_price = models.FloatField(null=True)
converted_currency = models.CharField(max_length=3, blank=True, default="") converted_currency = models.CharField(max_length=3, blank=True, default="")
needs_price_update = models.BooleanField(default=True, db_index=True)
price_per_game = GeneratedField( price_per_game = GeneratedField(
expression=Coalesce(F("converted_price"), F("price"), 0) / F("num_purchases"), expression=Coalesce(F("converted_price"), F("price"), 0) / F("num_purchases"),
output_field=models.FloatField(), output_field=models.FloatField(),
@@ -240,12 +241,6 @@ class Purchase(models.Model):
def is_game(self): def is_game(self):
return self.type == self.GAME return self.type == self.GAME
def price_or_currency_differ_from(self, purchase_to_compare):
return (
self.price != purchase_to_compare.price
or self.price_currency != purchase_to_compare.price_currency
)
def refund(self): def refund(self):
self.date_refunded = timezone.now() self.date_refunded = timezone.now()
self.save() self.save()
@@ -255,19 +250,6 @@ class Purchase(models.Model):
raise ValidationError( raise ValidationError(
f"{self.get_type_display()} must have a related purchase." f"{self.get_type_display()} must have a related purchase."
) )
if self.pk is not None:
# Retrieve the existing instance from the database
existing_purchase = Purchase.objects.get(pk=self.pk)
# If price has changed, reset converted fields
if existing_purchase.price_or_currency_differ_from(self):
from games.tasks import currency_to
exchange_rate = get_or_create_rate(
self.price_currency, currency_to, self.date_purchased.year
)
if exchange_rate:
self.converted_price = floatformat(self.price * exchange_rate, 0)
self.converted_currency = currency_to
super().save(*args, **kwargs) super().save(*args, **kwargs)
+23
View File
@@ -17,6 +17,29 @@ from games.models import Game, GameStatusChange, Purchase, Session
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
logger = logging.getLogger("games") logger = logging.getLogger("games")
@receiver(pre_save, sender=Purchase)
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
def store_purchase_price_snapshot(sender, instance, **kwargs):
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
"""Store old price values before save so we can detect changes."""
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
if instance.pk is not None:
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
try:
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
old_instance = sender.objects.get(pk=instance.pk)
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
instance._old_price = old_instance.price
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
instance._old_currency = old_instance.price_currency
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
except sender.DoesNotExist:
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
pass
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
@receiver(post_save, sender=Purchase)
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
def mark_needs_price_update(sender, instance, created, **kwargs):
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
"""Mark purchase for price update if price or currency changed."""
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
if not created and hasattr(instance, "_old_price"):
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
if (
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
instance.price != instance._old_price
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
or instance.price_currency != instance._old_currency
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
):
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
sender.objects.filter(pk=instance.pk).update(needs_price_update=True)
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
@receiver(m2m_changed, sender=Purchase.games.through) @receiver(m2m_changed, sender=Purchase.games.through)
def update_num_purchases(sender, instance, action, reverse, **kwargs): def update_num_purchases(sender, instance, action, reverse, **kwargs):
if not reverse and action.startswith("post_"): if not reverse and action.startswith("post_"):
lukas marked this conversation as resolved
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
Review

This signal handler fetches the old instance from the DB on every update. The old code in save() also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.

This signal handler fetches the old instance from the DB on every update. The old code in `save()` also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off.
+45 -35
View File
@@ -1,6 +1,7 @@
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
import logging import logging
import requests import requests
from django.db import models
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
from django.template.defaultfilters import floatformat from django.template.defaultfilters import floatformat
logger = logging.getLogger("games") logger = logging.getLogger("games")
@@ -12,41 +13,18 @@ currency_to = "CZK"
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
currency_to = currency_to.upper() currency_to = currency_to.upper()
def save_converted_info(purchase, converted_price, converted_currency): def _get_exchange_rate(currency_from, currency_to, year):
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
logger.info( logger.debug(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
f"Setting converted price of {purchase} to {converted_price} {converted_currency} (originally {purchase.price} {purchase.price_currency})"
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
)
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase.converted_price = converted_price
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase.converted_currency = converted_currency
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase.save()
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
def convert_prices():
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchases = Purchase.objects.filter(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
converted_price__isnull=True, converted_currency=""
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
)
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if purchases.count() == 0:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
logger.info("[convert_prices]: No prices to convert.")
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
for purchase in purchases:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if purchase.price_currency.upper() == currency_to or purchase.price == 0:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
save_converted_info(purchase, purchase.price, currency_to)
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
continue
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
year = purchase.date_purchased.year
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
currency_from = purchase.price_currency.upper()
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
exchange_rate = ExchangeRate.objects.filter(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
currency_from=currency_from, currency_to=currency_to, year=year
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
).first()
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
logger.info(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
f"[convert_prices]: Looking for exchange rate in database: {currency_from}->{currency_to}" f"[convert_prices]: Looking for exchange rate in database: {currency_from}->{currency_to}"
) )
if not exchange_rate: rate = ExchangeRate.objects.filter(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
logger.info( currency_from=currency_from, currency_to=currency_to, year=year
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
).first()
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if not rate:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
logger.debug(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
f"[convert_prices]: Getting exchange rate from {currency_from} to {currency_to} for {year}..." f"[convert_prices]: Getting exchange rate from {currency_from} to {currency_to} for {year}..."
) )
try: try:
# this API endpoint only accepts lowercase currency string
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
response = requests.get( response = requests.get(
f"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@{year}-01-01/v1/currencies/{currency_from.lower()}.json" f"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@{year}-01-01/v1/currencies/{currency_from.lower()}.json"
) )
@@ -54,7 +32,6 @@ def convert_prices():
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
data = response.json() data = response.json()
currency_from_data = data.get(currency_from.lower()) currency_from_data = data.get(currency_from.lower())
rate = currency_from_data.get(currency_to.lower()) rate = currency_from_data.get(currency_to.lower())
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if rate: if rate:
logger.info(f"[convert_prices]: Got {rate}, saving...") logger.info(f"[convert_prices]: Got {rate}, saving...")
exchange_rate = ExchangeRate.objects.create( exchange_rate = ExchangeRate.objects.create(
@@ -63,17 +40,50 @@ def convert_prices():
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
year=year, year=year,
rate=floatformat(rate, 2), rate=floatformat(rate, 2),
) )
rate = exchange_rate.rate
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
else: else:
logger.info("[convert_prices]: Could not get an exchange rate.") logger.info("[convert_prices]: Could not get an exchange rate.")
except requests.RequestException as e: except requests.RequestException as e:
logger.info( logger.info(
f"[convert_prices]: Failed to fetch exchange rate for {currency_from}->{currency_to} in {year}: {e}" f"[convert_prices]: Failed to fetch exchange rate for {currency_from}->{currency_to} in {year}: {e}"
) )
if exchange_rate: elif rate:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
save_converted_info( rate = rate.rate
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
return rate
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
def _save_converted_price(purchase, converted_price, needs_update):
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
logger.info(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
f"Setting converted price of {purchase} to {converted_price} {currency_to} (originally {purchase.price} {purchase.price_currency})"
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
)
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase.converted_price = converted_price
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase.converted_currency = currency_to
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if needs_update:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase.needs_price_update = False
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase.save(update_fields=["converted_price", "converted_currency", "needs_price_update"])
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
def convert_prices():
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchases = Purchase.objects.filter(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
models.Q(needs_price_update=True) | models.Q(converted_price__isnull=True)
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
).distinct()
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if purchases.count() == 0:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
logger.info("[convert_prices]: No prices to convert.")
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
return
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
for purchase in purchases:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
needs_update = purchase.needs_price_update
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if purchase.price_currency.upper() == currency_to or purchase.price == 0:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
_save_converted_price(purchase, purchase.price, needs_update)
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
continue
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
year = purchase.date_purchased.year
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
currency_from = purchase.price_currency.upper()
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
rate = _get_exchange_rate(currency_from, currency_to, year)
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
if rate:
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
_save_converted_price(
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
purchase, purchase,
floatformat(purchase.price * exchange_rate.rate, 0), floatformat(purchase.price * rate, 0),
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
currency_to, needs_update,
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
) )
lukas marked this conversation as resolved
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
Review

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to rate.

_get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to `rate`.
Review

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.

Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
+100 -1
View File
@@ -1,3 +1,102 @@
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
from datetime import date
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
from django.test import TestCase from django.test import TestCase
# Create your tests here. from games.models import Game, Platform, Purchase
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
from games.tasks import convert_prices
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
class PurchaseNeedsPriceUpdateTest(TestCase):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
def setUp(self):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.platform = Platform.objects.create(name="PC", icon="pc", group="PC")
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.game = Game.objects.create(name="Test Game", platform=self.platform)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
def test_new_purchase_has_needs_price_update_true(self):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase = Purchase.objects.create(
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price=50.0,
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price_currency="USD",
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
date_purchased=date(2025, 1, 1),
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.games.add(self.game)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.assertTrue(purchase.needs_price_update)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
def test_convert_prices_sets_flag_to_false(self):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase = Purchase.objects.create(
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price=50.0,
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price_currency="USD",
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
date_purchased=date(2025, 1, 1),
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.games.add(self.game)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.assertTrue(purchase.needs_price_update)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
convert_prices()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.refresh_from_db()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.assertFalse(purchase.needs_price_update)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
def test_price_change_sets_needs_price_update(self):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase = Purchase.objects.create(
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price=50.0,
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price_currency="USD",
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
date_purchased=date(2025, 1, 1),
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.games.add(self.game)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_price = 1000
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_currency = "CZK"
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.needs_price_update = False
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.save()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.price = 60.0
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.save()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.refresh_from_db()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.assertTrue(purchase.needs_price_update)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
def test_currency_change_sets_needs_price_update(self):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase = Purchase.objects.create(
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price=50.0,
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price_currency="USD",
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
date_purchased=date(2025, 1, 1),
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.games.add(self.game)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_price = 1000
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_currency = "CZK"
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.needs_price_update = False
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.save()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.price_currency = "EUR"
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.save()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.refresh_from_db()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.assertTrue(purchase.needs_price_update)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
def test_name_change_does_not_set_needs_price_update(self):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase = Purchase.objects.create(
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price=50.0,
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price_currency="USD",
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
date_purchased=date(2025, 1, 1),
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.games.add(self.game)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_price = 1000
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_currency = "CZK"
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.needs_price_update = False
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.save()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.name = "New Name"
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.save()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.refresh_from_db()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.assertFalse(purchase.needs_price_update)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
def test_convert_prices_skips_already_converted(self):
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase = Purchase.objects.create(
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price=50.0,
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
price_currency="USD",
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
date_purchased=date(2025, 1, 1),
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.games.add(self.game)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_price = 1000
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.converted_currency = "CZK"
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.needs_price_update = False
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.save()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
convert_prices()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
purchase.refresh_from_db()
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
self.assertFalse(purchase.needs_price_update)
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
lukas marked this conversation as resolved
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
Review

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.

override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.