From b98d576c6f2dcc47b9ab2c88f5b831bfd3025380 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org>
Date: Thu, 14 Mar 2024 17:34:06 +0100
Subject: [PATCH] Add `finances.PubFrac` model (to succeed
 `journals.OrgPubFraction`)

---
 scipost_django/finances/admin.py              | 25 ++++++++++-
 .../finances/migrations/0032_pubfrac.py       | 29 +++++++++++++
 .../migrations/0033_populate_pubfracs.py      | 30 ++++++++++++++
 scipost_django/finances/models/__init__.py    |  2 +
 scipost_django/finances/models/pubfrac.py     | 41 +++++++++++++++++++
 scipost_django/journals/admin.py              | 12 +++++-
 6 files changed, 136 insertions(+), 3 deletions(-)
 create mode 100644 scipost_django/finances/migrations/0032_pubfrac.py
 create mode 100644 scipost_django/finances/migrations/0033_populate_pubfracs.py
 create mode 100644 scipost_django/finances/models/pubfrac.py

diff --git a/scipost_django/finances/admin.py b/scipost_django/finances/admin.py
index f59c8229e..7aceacfcb 100644
--- a/scipost_django/finances/admin.py
+++ b/scipost_django/finances/admin.py
@@ -8,6 +8,7 @@ from .models import (
     Subsidy,
     SubsidyPayment,
     SubsidyAttachment,
+    PubFrac,
     WorkLog,
     PeriodicReportType,
     PeriodicReport,
@@ -62,13 +63,35 @@ class SubsidyAttachmentAdmin(admin.ModelAdmin):
 
 
 
+@admin.register(PubFrac)
+class PubFracAdmin(admin.ModelAdmin):
+    list_display = [
+        "organization",
+        "doi_label_display",
+        "fraction",
+    ]
+    autocomplete_fields = [
+        "organization",
+        "publication",
+    ]
+    search_fields = [
+        "publication__doi_label",
+        "organization__name",
+        "organization__name_original",
+        "organization__acronym",
+    ]
+
+    @admin.display(description='doi label')
+    def doi_label_display(self, obj):
+        return (obj.publication.doi_label)
+
+
 @admin.register(WorkLog)
 class WorkLogAdmin(admin.ModelAdmin):
     autocomplete_fields = ["user"]
 
 
 
-
 admin.site.register(PeriodicReportType)
 
 admin.site.register(PeriodicReport)
diff --git a/scipost_django/finances/migrations/0032_pubfrac.py b/scipost_django/finances/migrations/0032_pubfrac.py
new file mode 100644
index 000000000..2d915d0a1
--- /dev/null
+++ b/scipost_django/finances/migrations/0032_pubfrac.py
@@ -0,0 +1,29 @@
+# Generated by Django 3.2.18 on 2024-03-14 15:58
+
+from decimal import Decimal
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0128_populate_submission_object_types'),
+        ('organizations', '0021_enable_unaccent'),
+        ('finances', '0031_alter_subsidyattachment_attachment'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='PubFrac',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('fraction', models.DecimalField(decimal_places=3, default=Decimal('0.000'), max_digits=4)),
+                ('organization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='pubfracs', to='organizations.organization')),
+                ('publication', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pubfracs', to='journals.publication')),
+            ],
+            options={
+                'unique_together': {('organization', 'publication')},
+            },
+        ),
+    ]
diff --git a/scipost_django/finances/migrations/0033_populate_pubfracs.py b/scipost_django/finances/migrations/0033_populate_pubfracs.py
new file mode 100644
index 000000000..86aad1297
--- /dev/null
+++ b/scipost_django/finances/migrations/0033_populate_pubfracs.py
@@ -0,0 +1,30 @@
+# Generated by Django 3.2.18 on 2024-03-14 15:59
+
+from django.db import migrations
+
+
+def populate_pubfracs(apps, schema_editor):
+    OrgPubFraction = apps.get_model("journals.OrgPubFraction")
+    PubFrac = apps.get_model("finances.PubFrac")
+
+    # Copy all data from OrgPubFraction to the new PubFrac
+    for opf in OrgPubFraction.objects.all():
+        pubfrac = PubFrac(
+            organization=opf.organization,
+            publication=opf.publication,
+            fraction=opf.fraction)
+        pubfrac.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('finances', '0032_pubfrac'),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            populate_pubfracs,
+            reverse_code=migrations.RunPython.noop,
+            )
+    ]
diff --git a/scipost_django/finances/models/__init__.py b/scipost_django/finances/models/__init__.py
index e7fa05003..a3406bafc 100644
--- a/scipost_django/finances/models/__init__.py
+++ b/scipost_django/finances/models/__init__.py
@@ -8,6 +8,8 @@ from .periodic_report import (
     PeriodicReport,
 )
 
+from .pubfrac import PubFrac
+
 from .subsidy import Subsidy
 
 from .subsidy_payment import SubsidyPayment
diff --git a/scipost_django/finances/models/pubfrac.py b/scipost_django/finances/models/pubfrac.py
new file mode 100644
index 000000000..836c8fa26
--- /dev/null
+++ b/scipost_django/finances/models/pubfrac.py
@@ -0,0 +1,41 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from decimal import Decimal
+
+from django.db import models
+
+
+class PubFrac(models.Model):
+    """
+    A fraction of a given Publication related to an Organization, for expenditure redistribution.
+
+    Fractions for a given Publication should sum up to one.
+
+    This data is used to compile publicly-displayed information on Organizations
+    as well as to set suggested contributions from sponsoring Organizations.
+    """
+
+    organization = models.ForeignKey(
+        "organizations.Organization",
+        on_delete=models.CASCADE,
+        related_name="pubfracs",
+        blank=True,
+        null=True,
+    )
+    publication = models.ForeignKey(
+        "journals.Publication", on_delete=models.CASCADE, related_name="pubfracs"
+    )
+    fraction = models.DecimalField(
+        max_digits=4, decimal_places=3, default=Decimal("0.000")
+    )
+
+    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
+        ))
diff --git a/scipost_django/journals/admin.py b/scipost_django/journals/admin.py
index f8265c6ed..b6e5cb157 100644
--- a/scipost_django/journals/admin.py
+++ b/scipost_django/journals/admin.py
@@ -22,6 +22,7 @@ from journals.models import (
     PublicationResource,
 )
 
+from finances.models import PubFrac
 from scipost.models import Contributor
 from submissions.models import Submission
 
@@ -94,6 +95,14 @@ class OrgPubFractionInline(admin.TabularInline):
     ]
 
 
+class PubFracInline(admin.TabularInline):
+    model = PubFrac
+    list_display = ("organization", "publication", "fraction")
+    autocomplete_fields = [
+        "organization",
+    ]
+
+
 @admin.register(Publication)
 class PublicationAdmin(admin.ModelAdmin):
     exclude = ["cf_citation", "cf_author_affiliation_indices_list"]
@@ -112,6 +121,7 @@ class PublicationAdmin(admin.ModelAdmin):
         AuthorsInline,
         ReferenceInline,
         OrgPubFractionInline,
+        PubFracInline,
         PublicationResourceInline,
     ]
     autocomplete_fields = [
@@ -202,5 +212,3 @@ class PublicationUpdateAdmin(admin.ModelAdmin):
     autocomplete_fields = [
         "publication",
     ]
-
-
-- 
GitLab