From e8f9aa1e38d6a048482ad23a39ad01ea72f93417 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org>
Date: Fri, 15 Mar 2024 06:39:42 +0100
Subject: [PATCH] Make PubFrac value a calculated field (cf_value)

---
 scipost_django/finances/admin.py              |  1 +
 .../migrations/0035_pubfrac_cf_value.py       | 18 ++++++++++
 .../0036_populate_pubfrac_cf_value.py         | 36 +++++++++++++++++++
 scipost_django/finances/models/pubfrac.py     | 20 ++++++++---
 4 files changed, 70 insertions(+), 5 deletions(-)
 create mode 100644 scipost_django/finances/migrations/0035_pubfrac_cf_value.py
 create mode 100644 scipost_django/finances/migrations/0036_populate_pubfrac_cf_value.py

diff --git a/scipost_django/finances/admin.py b/scipost_django/finances/admin.py
index 7aceacfcb..36cf1bf8d 100644
--- a/scipost_django/finances/admin.py
+++ b/scipost_django/finances/admin.py
@@ -69,6 +69,7 @@ class PubFracAdmin(admin.ModelAdmin):
         "organization",
         "doi_label_display",
         "fraction",
+        "cf_value",
     ]
     autocomplete_fields = [
         "organization",
diff --git a/scipost_django/finances/migrations/0035_pubfrac_cf_value.py b/scipost_django/finances/migrations/0035_pubfrac_cf_value.py
new file mode 100644
index 000000000..364c59f38
--- /dev/null
+++ b/scipost_django/finances/migrations/0035_pubfrac_cf_value.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.10 on 2024-03-15 04:11
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("finances", "0034_alter_worklog_content_type_alter_worklog_user"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="pubfrac",
+            name="cf_value",
+            field=models.PositiveIntegerField(blank=True, null=True),
+        ),
+    ]
diff --git a/scipost_django/finances/migrations/0036_populate_pubfrac_cf_value.py b/scipost_django/finances/migrations/0036_populate_pubfrac_cf_value.py
new file mode 100644
index 000000000..ffbe52be7
--- /dev/null
+++ b/scipost_django/finances/migrations/0036_populate_pubfrac_cf_value.py
@@ -0,0 +1,36 @@
+# Generated by Django 4.2.10 on 2024-03-15 04:11
+
+from django.db import migrations
+
+
+def populate_pubfrac_cf_value(apps, schema_editor):
+    PubFrac = apps.get_model("finances.PubFrac")
+    Journal = apps.get_model("journals.Journal")
+
+    # Some contortions required since model methods not available in migrations
+    for pf in PubFrac.objects.all():
+        if pf.publication.in_journal:
+            journal = Journal.objects.get(pk=pf.publication.in_journal.id)
+        elif pf.publication.in_issue.in_journal:
+            journal = Journal.objects.get(pk=pf.publication.in_issue.in_journal.id)
+        else:
+            journal = Journal.objects.get(pk=pf.publication.in_issue.in_volume.in_journal.id)
+        cost_per_publication = journal.cost_info[pf.publication.publication_date.year] \
+            if pf.publication.publication_date.year in journal.cost_info else \
+               journal.cost_info["default"]
+        pf.cf_value = int(pf.fraction * cost_per_publication)
+        pf.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("finances", "0035_pubfrac_cf_value"),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            populate_pubfrac_cf_value,
+            reverse_code=migrations.RunPython.noop,
+        )
+    ]
diff --git a/scipost_django/finances/models/pubfrac.py b/scipost_django/finances/models/pubfrac.py
index 836c8fa26..6207be70e 100644
--- a/scipost_django/finances/models/pubfrac.py
+++ b/scipost_django/finances/models/pubfrac.py
@@ -5,6 +5,8 @@ __license__ = "AGPL v3"
 from decimal import Decimal
 
 from django.db import models
+from django.db.models.signals import pre_save
+from django.dispatch import receiver
 
 
 class PubFrac(models.Model):
@@ -31,11 +33,19 @@ class PubFrac(models.Model):
         max_digits=4, decimal_places=3, default=Decimal("0.000")
     )
 
+    # Calculated field
+    cf_value = models.PositiveIntegerField(blank=True, null=True)
+
     class Meta:
         unique_together = (("organization", "publication"),)
 
-    @property
-    def value(self):
-        return int(self.fraction * self.publication.get_journal().cost_per_publication(
-            self.publication.publication_date.year
-        ))
+
+@receiver(pre_save, sender=PubFrac)
+def calculate_cf_value(sender, instance: PubFrac, **kwargs):
+    """Calculate the cf_value field before saving."""
+    instance.cf_value = int(
+        instance.fraction * instance.publication.get_journal(
+        ).cost_per_publication(
+            instance.publication.publication_date.year
+        )
+    )
-- 
GitLab