diff --git a/scipost_django/finances/forms.py b/scipost_django/finances/forms.py
index 3d13edceaf7e5ca2fba66c5134f55e1d2f36536c..163678983c83c3c3efae461926e297ff856204ab 100644
--- a/scipost_django/finances/forms.py
+++ b/scipost_django/finances/forms.py
@@ -58,7 +58,6 @@ class SubsidyForm(forms.ModelForm):
     class Meta:
         model = Subsidy
         fields = [
-            "algorithm",
             "organization",
             "subsidy_type",
             "description",
diff --git a/scipost_django/finances/management/commands/compensate_pubfracs.py b/scipost_django/finances/management/commands/compensate_pubfracs.py
new file mode 100644
index 0000000000000000000000000000000000000000..2450a7e24a103dc0670054bf9fb0c6a4b04bfa13
--- /dev/null
+++ b/scipost_django/finances/management/commands/compensate_pubfracs.py
@@ -0,0 +1,19 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.core.management.base import BaseCommand
+
+from finances.models import Subsidy
+
+
+class Command(BaseCommand):
+    help = "Applies compensations from Subsidies to PubFracs"
+
+    def handle(self, *args, **kwargs):
+        # All Subsidy-givers first compensate themselves, starting from oldest Subsidy
+        for subsidy in Subsidy.objects.obtained().order_by("date_from"):
+            subsidy.compensate_own_pubfracs()
+        # then their children, again starting from oldest Subsidy
+        for subsidy in Subsidy.objects.obtained().order_by("date_from"):
+            subsidy.compensate_children_pubfracs()
diff --git a/scipost_django/finances/migrations/0033_populate_pubfracs.py b/scipost_django/finances/migrations/0033_populate_pubfracs.py
index d4a07844f03c1a91283da5339fa3ad8112aa0b64..17cec8580a14af4267e8434aba63db447f9d8c32 100644
--- a/scipost_django/finances/migrations/0033_populate_pubfracs.py
+++ b/scipost_django/finances/migrations/0033_populate_pubfracs.py
@@ -4,18 +4,18 @@ 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()
-
+    # 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()
+    pass # 2024-03-20 not needed anymore: PubFracs are algorithmically calculated
 
 class Migration(migrations.Migration):
 
diff --git a/scipost_django/finances/migrations/0044_remove_subsidy_algorithm_and_more.py b/scipost_django/finances/migrations/0044_remove_subsidy_algorithm_and_more.py
new file mode 100644
index 0000000000000000000000000000000000000000..7202f1dc7b5acdef2a6a6d26b6109eba7108dc69
--- /dev/null
+++ b/scipost_django/finances/migrations/0044_remove_subsidy_algorithm_and_more.py
@@ -0,0 +1,21 @@
+# Generated by Django 4.2.10 on 2024-03-20 15:28
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("finances", "0043_alter_pubfrac_cf_value"),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name="subsidy",
+            name="algorithm",
+        ),
+        migrations.RemoveField(
+            model_name="subsidy",
+            name="algorithm_data",
+        ),
+    ]
diff --git a/scipost_django/finances/models/subsidy.py b/scipost_django/finances/models/subsidy.py
index 17d9e6733ea19c2e37805ed73af8b8e649b598ba..8467098b9d7b3870c531bb056588dbb1e09f35df 100644
--- a/scipost_django/finances/models/subsidy.py
+++ b/scipost_django/finances/models/subsidy.py
@@ -39,64 +39,6 @@ class Subsidy(models.Model):
     after which the object of the Subsidy is officially terminated.
     """
 
-    ALGORITHM_ANY_AFF = "any_aff"
-    ALGORITHM_ANY_CTRY = "any_ctry"
-    ALGORITHM_ANY_ORGS = "any_orgs"
-    ALGORITHM_ANY_SPEC = "any_spec"
-    ALGORITHM_ALL_AFF = "all_aff"
-    ALGORITHM_ALL_CTRY = "all_ctry"
-    ALGORITHM_ALL_ORGS = "all_orgs"
-    ALGORITHM_ALL_SPEC = "all_spec"
-    ALGORITHM_ALL_FUND = "all_fund"
-    ALGORITHM_RESERVES = "reserves"
-    ALGORITHM_CHOICES = (
-        (ALGORITHM_ANY_AFF, "Any PubFrac with affiliation to org"),
-        (
-            ALGORITHM_ANY_CTRY,
-            "Any PubFrac with an affiliation in given list of countries",
-        ),
-        (ALGORITHM_ANY_ORGS, "Any PubFrac with an affiliation in given list of orgs"),
-        (
-            ALGORITHM_ANY_SPEC,
-            "Any PubFrac of publication in given list of specialties",
-        ),
-        (
-            ALGORITHM_ALL_AFF,
-            (
-                "All PubFracs of publication with at least one author "
-                "with affiliation to org"
-            ),
-        ),
-        (
-            ALGORITHM_ALL_CTRY,
-            (
-                "All PubFracs of publications having at least one affiliation "
-                "in given list of countries"
-            ),
-        ),
-        (
-            ALGORITHM_ALL_ORGS,
-            (
-                "All PubFracs of publications having at least "
-                "one affiliation in given list of orgs"
-            ),
-        ),
-        (
-            ALGORITHM_ALL_SPEC,
-            "All PubFracs of publication in given list of specialties",
-        ),
-        (
-            ALGORITHM_ALL_FUND,
-            "All PubFracs of publication acknowledging org in Funders",
-        ),
-        (ALGORITHM_RESERVES, "Allocate to reserves fund"),
-    )
-    algorithm = models.CharField(
-        max_length=32,
-        choices=ALGORITHM_CHOICES,
-        default=ALGORITHM_RESERVES,
-    )
-    algorithm_data = models.JSONField(default=dict)
     organization = models.ForeignKey["Organization"](
         "organizations.Organization", on_delete=models.CASCADE
     )
@@ -185,28 +127,37 @@ class Subsidy(models.Model):
         """
         return self.amount == self.payments.aggregate(Sum("amount"))["amount__sum"]
 
-    @property
-    def allocatable(self):
+    def compensate(self, pubfracs: PubFracQuerySet):
         """
-        Determine whether this Subsidy can be allocated.
+        Allocate subsidy to uncompensated pubfracs in queryset, up to depletion.
         """
-        implemented_algorithms = [self.ALGORITHM_ANY_AFF, self.ALGORITHM_ALL_AFF]
-        return (
-            self.status != SUBSIDY_WITHDRAWN
-            and self.algorithm != self.ALGORITHM_RESERVES
-            and self.algorithm in implemented_algorithms
-        )
+        for pubfrac in pubfracs.uncompensated():
+            if pubfrac.cf_value <= self.remainder:
+                pubfrac.compensated_by = self
+                pubfrac.save()
 
-    def allocate(self):
+    def compensate_own_pubfracs(self):
         """
-        Allocate the funds according to the algorithm specific by the instance.
+        Compensate PubFracs with direct affiliation to Subsidy-giver.
         """
-        from finances.allocate import allocate_to_any_aff, allocate_to_all_aff
+        max_year = self.date_until.year if self.date_until else self.date_from.year
+        pubfracs = self.organization.pubfracs.filter(
+            publication__publication_date__year__gte=self.date_from.year,
+            publication__publication_date__year__lte=max_year,
+        )
+        self.compensate(pubfracs)
 
-        if self.algorithm == self.ALGORITHM_ANY_AFF:
-            allocate_to_any_aff(self)
-        elif self.algorithm == self.ALGORITHM_ALL_AFF:
-            allocate_to_all_aff(self)
+    def compensate_children_pubfracs(self):
+        """
+        Compensate PubFracs with direct affiliation to Subsidy-giver's children Organizations.
+        """
+        max_year = self.date_until.year if self.date_until else self.date_from.year
+        for child in self.organization.children.all():
+            pubfracs = child.pubfracs.filter(
+                publication__publication_date__year__gte=self.date_from.year,
+                publication__publication_date__year__lte=max_year,
+            )
+            self.compensate(pubfracs)
 
     @property
     def total_compensations(self):
diff --git a/scipost_django/organizations/models.py b/scipost_django/organizations/models.py
index 4ffeb46ac0195f6bb94a1c97a43d40d23dd616de..826bffb632818d75fa31e2bf97e6f3af4a0134b2 100644
--- a/scipost_django/organizations/models.py
+++ b/scipost_django/organizations/models.py
@@ -4,7 +4,6 @@ __license__ = "AGPL v3"
 
 import datetime
 import hashlib
-import pytz
 import random
 import string
 
@@ -17,6 +16,15 @@ from django.urls import reverse
 
 from django_countries.fields import CountryField
 
+from scipost.constants import TITLE_CHOICES
+from scipost.fields import ChoiceArrayField
+from scipost.models import Contributor
+from affiliates.models import AffiliatePublication
+from colleges.models import Fellowship
+from finances.models import PubFrac
+from journals.models import Journal, Publication
+from profiles.models import Profile
+
 from .constants import (
     ORGANIZATION_TYPES,
     ORGTYPE_PRIVATE_BENEFACTOR,
@@ -27,15 +35,6 @@ from .constants import (
 )
 from .managers import OrganizationQuerySet
 
-from scipost.constants import TITLE_CHOICES
-from scipost.fields import ChoiceArrayField
-from scipost.models import Contributor
-from affiliates.models import AffiliatePublication
-from colleges.models import Fellowship
-from finances.models import PubFrac
-from journals.models import Journal, Publication
-from profiles.models import Profile
-
 
 class OrganizationLogo(models.Model):
     """