From 580e15c06230fa4c5f861f2141a01b9508ec22bb Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Fri, 7 Apr 2023 09:03:29 +0000 Subject: [PATCH 01/29] add module field for regional --- ...0033_alter_queryandconvertconfig_module.py | 25 +++++++++++++++++++ src/holon/models/config/query_and_convert.py | 11 +++++--- 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 src/holon/migrations/0033_alter_queryandconvertconfig_module.py diff --git a/src/holon/migrations/0033_alter_queryandconvertconfig_module.py b/src/holon/migrations/0033_alter_queryandconvertconfig_module.py new file mode 100644 index 000000000..1fa479ab8 --- /dev/null +++ b/src/holon/migrations/0033_alter_queryandconvertconfig_module.py @@ -0,0 +1,25 @@ +# Generated by Django 4.1.7 on 2023-04-07 09:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0032_merge_20230406_1342"), + ] + + operations = [ + migrations.AlterField( + model_name="queryandconvertconfig", + name="module", + field=models.CharField( + choices=[ + ("upscaling", "Upscaling"), + ("upscaling-regional", "Upscaling Regional"), + ("cost", "Cost"), + ("costbenefit", "Costbenefit"), + ], + max_length=255, + ), + ), + ] diff --git a/src/holon/models/config/query_and_convert.py b/src/holon/models/config/query_and_convert.py index fab91f706..8eb08f941 100644 --- a/src/holon/models/config/query_and_convert.py +++ b/src/holon/models/config/query_and_convert.py @@ -1,14 +1,15 @@ from django.db import models -from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from django.utils.translation import gettext_lazy as _ +from modelcluster.fields import ParentalKey +from modelcluster.models import ClusterableModel +from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from holon.models.scenario import Scenario -from modelcluster.models import ClusterableModel -from modelcluster.fields import ParentalKey class QueryCovertModuleType(models.TextChoices): UPSCALING = "upscaling" + UPSCALING_REGIONAL = "upscaling-regional" COST = "cost" COSTBENEFIT = "costbenefit" @@ -44,7 +45,9 @@ class QueryAndConvertConfig(ClusterableModel): def __str__(self): if self.module == QueryCovertModuleType.UPSCALING: - return f"ETM opschalingsconfiguratie ({self.name})" + return f"ETM nationale opschalingsconfiguratie ({self.name})" + if self.module == QueryCovertModuleType.UPSCALING_REGIONAL: + return f"ETM regionale opschalingsconfiguratie ({self.name})" if self.module == QueryCovertModuleType.COST: return f"Kostenmodule configuratie ({self.name})" if self.module == QueryCovertModuleType.COSTBENEFIT: From c685003894241af71119827b33677187776c707c Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Fri, 7 Apr 2023 12:58:09 +0000 Subject: [PATCH 02/29] add fields of 499 --- ...0033_alter_queryandconvertconfig_module.py | 25 ----------- ...ry_interactive_upscaling_title_and_more.py | 45 +++++++++++++++++++ ..._interactive_upscaling_comment_and_more.py | 32 +++++++++++++ src/holon/models/config/etm_query.py | 21 ++++++--- src/holon/models/config/query_and_convert.py | 11 +++++ 5 files changed, 103 insertions(+), 31 deletions(-) delete mode 100644 src/holon/migrations/0033_alter_queryandconvertconfig_module.py create mode 100644 src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py create mode 100644 src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py diff --git a/src/holon/migrations/0033_alter_queryandconvertconfig_module.py b/src/holon/migrations/0033_alter_queryandconvertconfig_module.py deleted file mode 100644 index 1fa479ab8..000000000 --- a/src/holon/migrations/0033_alter_queryandconvertconfig_module.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 09:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0032_merge_20230406_1342"), - ] - - operations = [ - migrations.AlterField( - model_name="queryandconvertconfig", - name="module", - field=models.CharField( - choices=[ - ("upscaling", "Upscaling"), - ("upscaling-regional", "Upscaling Regional"), - ("cost", "Cost"), - ("costbenefit", "Costbenefit"), - ], - max_length=255, - ), - ), - ] diff --git a/src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py b/src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py new file mode 100644 index 000000000..2f2b878c9 --- /dev/null +++ b/src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py @@ -0,0 +1,45 @@ +# Generated by Django 4.1.7 on 2023-04-07 12:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0032_merge_20230406_1342"), + ] + + operations = [ + migrations.AddField( + model_name="etmquery", + name="interactive_upscaling_title", + field=models.CharField( + blank=True, + help_text="Title of the explaination of upscaling. For instance, the category of the upscaling component ('Zon op dak').", + max_length=255, + null=True, + ), + ), + migrations.AddField( + model_name="queryandconvertconfig", + name="interactive_upscaling_comment", + field=models.CharField( + blank=True, + help_text="Use this field to explain the query in the front-end. This field is rendered next to the KPI selection radio (that toggles between local, intermediate and national level)", + max_length=255, + null=True, + ), + ), + migrations.AlterField( + model_name="queryandconvertconfig", + name="module", + field=models.CharField( + choices=[ + ("upscaling", "Upscaling"), + ("upscaling-regional", "Upscaling Regional"), + ("cost", "Cost"), + ("costbenefit", "Costbenefit"), + ], + max_length=255, + ), + ), + ] diff --git a/src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py b/src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py new file mode 100644 index 000000000..071bf81da --- /dev/null +++ b/src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 4.1.7 on 2023-04-07 12:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0033_etmquery_interactive_upscaling_title_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="etmquery", + name="interactive_upscaling_comment", + field=models.TextField( + blank=True, + help_text="Use this field to explain the query in the front-end. Use {{variable}} for dynamic values. Options: local key-value pairs e.g., `scaling_factor`, `final_value` or `query_value` (to be implemented)", + max_length=255, + null=True, + ), + ), + migrations.AlterField( + model_name="queryandconvertconfig", + name="interactive_upscaling_comment", + field=models.TextField( + blank=True, + help_text="Use this field to explain the query in the front-end. This field is rendered next to the KPI selection radio (that toggles between local, intermediate and national level)", + max_length=255, + null=True, + ), + ), + ] diff --git a/src/holon/models/config/etm_query.py b/src/holon/models/config/etm_query.py index a9f4b9969..638b46e9c 100644 --- a/src/holon/models/config/etm_query.py +++ b/src/holon/models/config/etm_query.py @@ -1,11 +1,11 @@ from django.db import models -from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from django.utils.translation import gettext_lazy as _ - -from modelcluster.models import ClusterableModel from modelcluster.fields import ParentalKey +from modelcluster.models import ClusterableModel +from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from holon.models.config.query_and_convert import QueryAndConvertConfig +from main.blocks.rich_text_block import RichtextBlock class EndPoint(models.TextChoices): @@ -46,7 +46,15 @@ class ETMQuery(ClusterableModel): "Use this field to relate this query and conversion set to an interactive element (used for rendering in the front-end)" ), ) - interactive_upscaling_comment = models.CharField( + interactive_upscaling_title = models.CharField( + max_length=255, + blank=True, + null=True, + help_text=_( + "Title of the explaination of upscaling. For instance, the category of the upscaling component ('Zon op dak')." + ), + ) + interactive_upscaling_comment = models.TextField( max_length=255, blank=True, null=True, @@ -60,6 +68,9 @@ class ETMQuery(ClusterableModel): FieldPanel("data_type"), FieldPanel("etm_key"), FieldPanel("internal_key"), + FieldPanel("related_interactive_element"), + FieldPanel("interactive_upscaling_title"), + FieldPanel("interactive_upscaling_comment"), InlinePanel( "static_conversion_step", heading="Convert inputs/queries with static values", @@ -80,8 +91,6 @@ class ETMQuery(ClusterableModel): heading="Convert inputs/queries based on AnyLogic outcomes", label="AnyLogic result conversion (convert with AnyLogic outcomes)", ), - FieldPanel("related_interactive_element"), - FieldPanel("interactive_upscaling_comment"), ] def clean(self) -> None: diff --git a/src/holon/models/config/query_and_convert.py b/src/holon/models/config/query_and_convert.py index 8eb08f941..4cbd0ea59 100644 --- a/src/holon/models/config/query_and_convert.py +++ b/src/holon/models/config/query_and_convert.py @@ -5,6 +5,7 @@ from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from holon.models.scenario import Scenario +from main.blocks.rich_text_block import RichtextBlock class QueryCovertModuleType(models.TextChoices): @@ -24,11 +25,21 @@ class QueryAndConvertConfig(ClusterableModel): ) etm_scenario_id = models.IntegerField() + interactive_upscaling_comment = models.TextField( + max_length=255, + blank=True, + null=True, + help_text=_( + "Use this field to explain the query in the front-end. This field is rendered next to the KPI selection radio (that toggles between local, intermediate and national level)" + ), + ) + panels = [ FieldPanel("name"), FieldPanel("api_url"), FieldPanel("module"), FieldPanel("etm_scenario_id"), + FieldPanel("interactive_upscaling_comment"), InlinePanel( "etm_query", heading="Define your input and query statements here", From 9d851804c2e0e15f77855a5b10d3f6fdd53cc7d1 Mon Sep 17 00:00:00 2001 From: noracato Date: Fri, 7 Apr 2023 15:03:36 +0200 Subject: [PATCH 03/29] Add basic module and test for Cost Table --- src/holon/services/costs_table.py | 109 +++++++++ src/holon/tests/test_costs_table.py | 339 ++++++++++++++++++++++++++++ 2 files changed, 448 insertions(+) create mode 100644 src/holon/services/costs_table.py create mode 100644 src/holon/tests/test_costs_table.py diff --git a/src/holon/services/costs_table.py b/src/holon/services/costs_table.py new file mode 100644 index 000000000..0f0a156f0 --- /dev/null +++ b/src/holon/services/costs_table.py @@ -0,0 +1,109 @@ +"""Create a Costs&Benefits Table """ + + +class CostsTable: + def __init__(self, cost_items) -> None: + """cost_items is a generator of CostItems""" + self.table = cost_items + + @property + def table(self): + return self._table + + @table.setter + def table(self, cost_items): + self._table = {} + for item in cost_items: + self.__add_to_table(item) + + def __add_to_table(self, item): + """TODO: also work with subgroups""" + try: + self._table[item.from_actor.group][item.to_actor.group] += item.price + except KeyError: + self.__add_to_group(item) + + def __add_to_group(self, item): + try: + self._table[item.from_actor.group][item.to_actor.group] = item.price + except KeyError: + self.__add_from_group(item) + + def __add_from_group(self, item): + """ + Also needs to add self as None + --> are we sure like this we always have all the keys? + Probably in the output (as_totals) we need to rebuild the thing for all + the different groups to be present + """ + self._table[item.from_actor.group] = { + item.to_actor.group: item.price, + item.from_actor.group: None, + } + + def as_totals(self): + """TODO: returns the main groups view""" + + def as_detailed_view(self, group): + """TODO: returns detailed view for the group""" + + @classmethod + def from_al_output(cls, al_output, scenario): + actors = ActorWrapper.from_scenario(scenario) + return cls((CostItem.from_dict(item, actors) for item in al_output)) + + +class ActorWrapper: + def __init__(self, actors) -> None: + """Where actors is the Django equivalent of AR relation of Actors of the scenario""" + self.actors = actors + + def find(self, actor_name): + """ + Strips the AL prefix from the actor name and returns the corresponding Actor + TODO: Validate: does this actor exists -> what do we do if not + """ + return self.actors.get(int(actor_name[3:])) + + @classmethod + def from_scenario(cls, scenario): + return cls(scenario.prefetch_related("actors").objects.all()) + + +class CostItem: + """Represents one contract in the AL output""" + + def __init__(self, to_actor, from_actor, price) -> None: + self.from_actor = from_actor + self.to_actor = to_actor + self.price = price + + @staticmethod + def price_for(obj) -> float: + """ + Either FinancialTransactionVolume_eur is 0, or delivery_price is 0 + Add annual costs to this. + Returns the contracts total price + + Defaults to 0.0 + """ + return ( + obj.get("FinancialTransactionVolume_eur", 0.0) + + CostItem.delivery_price(obj) + + obj.get("annualFee_eur", 0.0) + ) + + @staticmethod + def delivery_price(obj) -> float: + """Check for the delivery price. If no prices sets defaults to 0""" + return obj.get("EnergyTransactionVolume_kWh", 0.0) * ( + obj.get("deliveryTax_eurpkWh", 0.0) + obj.get("deliveryPrice_eurpkWh", 0.0) + ) + + @classmethod + def from_dict(cls, obj: dict, actors: ActorWrapper): + return cls( + actors.find(obj["contractScope"]), + actors.find(obj["contractHolder"]), + CostItem.price_for(obj), + ) diff --git a/src/holon/tests/test_costs_table.py b/src/holon/tests/test_costs_table.py new file mode 100644 index 000000000..9b69f57b5 --- /dev/null +++ b/src/holon/tests/test_costs_table.py @@ -0,0 +1,339 @@ +from django.test import TestCase +from holon.models.scenario import Scenario +from holon.services.costs_table import CostsTable + + +class CostTableTestClass(TestCase): + fixtures = ["holon/tests/fixtures/merged-datamodel-ehub-config-fixture.json"] + + def test_table_totals(self): + """Test if the totals table is correctly set up""" + scenario = Scenario.objects.get(pk=1) + costs_table = CostsTable.from_al_output(self.__al_output, scenario) + + assert "CONNECTIONOWNER" in costs_table.keys + assert False + self.assertEqual(False, True) + + def __al_output(self): + return [ + { + "contractScope": "sup3", + "energyCarrier": "ELECTRICITY", + "contractType": "DELIVERY", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con4", + "annualFee_eur": 0.0, + "deliveryContractType": "ELECTRICITY_VARIABLE", + "deliveryPrice_eurpkWh": 0.0, + "feedinPrice_eurpkWh": 0.0, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "CONNECTION", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con4", + "annualFee_eur": 0.0, + "connectionContractType": "DEFAULT", + "nfATOstart_h": 20.0, + "nfATOend_h": 7.0, + "nfATOpower_kW": 2000.0, + }, + { + "contractScope": "gov9", + "energyCarrier": "ELECTRICITY", + "contractType": "TAX", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con4", + "annualFee_eur": 0.0, + "deliveryTax_eurpkWh": 0.15, + "feedinTax_eurpkWh": 0.15, + "proportionalTax_pct": 0.21, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "TRANSPORT", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con4", + "annualFee_eur": 0.0, + "transportContractType": "DEFAULT", + "bandwidthTreshold_kW": 0.0, + "bandwidthTariff_eurpkWh": 0.0, + }, + { + "contractScope": "sup3", + "energyCarrier": "ELECTRICITY", + "contractType": "DELIVERY", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con5", + "annualFee_eur": 0.0, + "deliveryContractType": "ELECTRICITY_VARIABLE", + "deliveryPrice_eurpkWh": 0.0, + "feedinPrice_eurpkWh": 0.0, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "CONNECTION", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con5", + "annualFee_eur": 0.0, + "connectionContractType": "DEFAULT", + "nfATOstart_h": 20.0, + "nfATOend_h": 7.0, + "nfATOpower_kW": 2000.0, + }, + { + "contractScope": "gov9", + "energyCarrier": "ELECTRICITY", + "contractType": "TAX", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con5", + "annualFee_eur": 0.0, + "deliveryTax_eurpkWh": 0.15, + "feedinTax_eurpkWh": 0.15, + "proportionalTax_pct": 0.21, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "TRANSPORT", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con5", + "annualFee_eur": 0.0, + "transportContractType": "DEFAULT", + "bandwidthTreshold_kW": 0.0, + "bandwidthTariff_eurpkWh": 0.0, + }, + { + "contractScope": "sup3", + "energyCarrier": "ELECTRICITY", + "contractType": "DELIVERY", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": -467137.9985450749, + "contractHolder": "con6", + "annualFee_eur": 0.0, + "deliveryContractType": "ELECTRICITY_VARIABLE", + "deliveryPrice_eurpkWh": 0.0, + "feedinPrice_eurpkWh": 0.0, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "CONNECTION", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con6", + "annualFee_eur": 0.0, + "connectionContractType": "DEFAULT", + "nfATOstart_h": 0.0, + "nfATOend_h": 0.0, + "nfATOpower_kW": 0.0, + }, + { + "contractScope": "gov9", + "energyCarrier": "ELECTRICITY", + "contractType": "TAX", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": -219082.7197801406, + "contractHolder": "con6", + "annualFee_eur": 0.0, + "deliveryTax_eurpkWh": 0.15, + "feedinTax_eurpkWh": 0.15, + "proportionalTax_pct": 0.21, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "TRANSPORT", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con6", + "annualFee_eur": 0.0, + "transportContractType": "DEFAULT", + "bandwidthTreshold_kW": 0.0, + "bandwidthTariff_eurpkWh": 0.0, + }, + { + "contractScope": "ope1", + "energyCarrier": "METHANE", + "contractType": "CONNECTION", + "EnergyTransactionVolume_kWh": 6315962.061147418, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con6", + "annualFee_eur": 0.0, + "connectionContractType": "DEFAULT", + "nfATOstart_h": 0.0, + "nfATOend_h": 0.0, + "nfATOpower_kW": 0.0, + }, + { + "contractScope": "gov9", + "energyCarrier": "METHANE", + "contractType": "TAX", + "EnergyTransactionVolume_kWh": 6315962.061147418, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con6", + "annualFee_eur": 0.0, + "deliveryTax_eurpkWh": 0.01, + "feedinTax_eurpkWh": 0.0, + "proportionalTax_pct": 0.21, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "CONNECTION", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con7", + "annualFee_eur": 0.0, + "connectionContractType": "DEFAULT", + "nfATOstart_h": 0.0, + "nfATOend_h": 0.0, + "nfATOpower_kW": 0.0, + }, + { + "contractScope": "sup3", + "energyCarrier": "ELECTRICITY", + "contractType": "DELIVERY", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con7", + "annualFee_eur": 0.0, + "deliveryContractType": "ELECTRICITY_VARIABLE", + "deliveryPrice_eurpkWh": 0.0, + "feedinPrice_eurpkWh": 0.0, + }, + { + "contractScope": "gov9", + "energyCarrier": "ELECTRICITY", + "contractType": "TAX", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con7", + "annualFee_eur": 0.0, + "deliveryTax_eurpkWh": 0.15, + "feedinTax_eurpkWh": 0.15, + "proportionalTax_pct": 0.21, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "TRANSPORT", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con7", + "annualFee_eur": 0.0, + "transportContractType": "DEFAULT", + "bandwidthTreshold_kW": 0.0, + "bandwidthTariff_eurpkWh": 0.0, + }, + { + "contractScope": "ope1", + "energyCarrier": "HYDROGEN", + "contractType": "CONNECTION", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con7", + "annualFee_eur": 0.0, + "connectionContractType": "DEFAULT", + "nfATOstart_h": 0.0, + "nfATOend_h": 0.0, + "nfATOpower_kW": 0.0, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "CONNECTION", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con8", + "annualFee_eur": 0.0, + "connectionContractType": "DEFAULT", + "nfATOstart_h": 0.0, + "nfATOend_h": 0.0, + "nfATOpower_kW": 0.0, + }, + { + "contractScope": "sup3", + "energyCarrier": "ELECTRICITY", + "contractType": "DELIVERY", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con8", + "annualFee_eur": 0.0, + "deliveryContractType": "ELECTRICITY_VARIABLE", + "deliveryPrice_eurpkWh": 0.0, + "feedinPrice_eurpkWh": 0.0, + }, + { + "contractScope": "gov9", + "energyCarrier": "ELECTRICITY", + "contractType": "TAX", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con8", + "annualFee_eur": 0.0, + "deliveryTax_eurpkWh": 0.15, + "feedinTax_eurpkWh": 0.15, + "proportionalTax_pct": 0.21, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "TRANSPORT", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "con8", + "annualFee_eur": 0.0, + "transportContractType": "DEFAULT", + "bandwidthTreshold_kW": 0.0, + "bandwidthTariff_eurpkWh": 0.0, + }, + { + "contractScope": "sup3", + "energyCarrier": "ELECTRICITY", + "contractType": "DELIVERY", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "hol2", + "annualFee_eur": 0.0, + "deliveryContractType": "ELECTRICITY_VARIABLE", + "deliveryPrice_eurpkWh": 0.0, + "feedinPrice_eurpkWh": 0.0, + }, + { + "contractScope": "ope1", + "energyCarrier": "ELECTRICITY", + "contractType": "TRANSPORT", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "hol2", + "annualFee_eur": 0.0, + "transportContractType": "DEFAULT", + "bandwidthTreshold_kW": 0.0, + "bandwidthTariff_eurpkWh": 0.0, + }, + { + "contractScope": "gov9", + "energyCarrier": "ELECTRICITY", + "contractType": "TAX", + "EnergyTransactionVolume_kWh": 0.0, + "FinancialTransactionVolume_eur": 0.0, + "contractHolder": "hol2", + "annualFee_eur": 0.0, + "deliveryTax_eurpkWh": 0.15, + "feedinTax_eurpkWh": 0.15, + "proportionalTax_pct": 0.21, + }, + ] From b7cd7d7a5d7842da782d8e8a42c19aec6d728cd6 Mon Sep 17 00:00:00 2001 From: noracato Date: Fri, 7 Apr 2023 16:20:28 +0200 Subject: [PATCH 04/29] Fix test of CostsTable --- src/holon/services/costs_table.py | 31 ++++++++++++++++++++++------- src/holon/tests/test_costs_table.py | 7 +++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/holon/services/costs_table.py b/src/holon/services/costs_table.py index 0f0a156f0..50c2ee9c6 100644 --- a/src/holon/services/costs_table.py +++ b/src/holon/services/costs_table.py @@ -19,13 +19,15 @@ def table(self, cost_items): def __add_to_table(self, item): """TODO: also work with subgroups""" try: - self._table[item.from_actor.group][item.to_actor.group] += item.price + self._table[item.from_group()][item.to_group()] += item.price except KeyError: + self.__add_from_group(item) + except TypeError: self.__add_to_group(item) def __add_to_group(self, item): try: - self._table[item.from_actor.group][item.to_actor.group] = item.price + self._table[item.from_group()][item.to_group()] = item.price except KeyError: self.__add_from_group(item) @@ -36,9 +38,10 @@ def __add_from_group(self, item): Probably in the output (as_totals) we need to rebuild the thing for all the different groups to be present """ - self._table[item.from_actor.group] = { - item.to_actor.group: item.price, - item.from_actor.group: None, + + self._table[item.from_group()] = { + item.to_group(): item.price, + item.from_group(): None, } def as_totals(self): @@ -63,11 +66,11 @@ def find(self, actor_name): Strips the AL prefix from the actor name and returns the corresponding Actor TODO: Validate: does this actor exists -> what do we do if not """ - return self.actors.get(int(actor_name[3:])) + return self.actors.get(id=int(actor_name[3:])) @classmethod def from_scenario(cls, scenario): - return cls(scenario.prefetch_related("actors").objects.all()) + return cls(scenario.actor_set) class CostItem: @@ -78,6 +81,20 @@ def __init__(self, to_actor, from_actor, price) -> None: self.to_actor = to_actor self.price = price + def from_group(self): + return CostItem.group(self.from_actor) + + def to_group(self): + return CostItem.group(self.to_actor) + + @staticmethod + def group(actor): + """Fallback to category if group is not defined""" + try: + return actor.group.name + except AttributeError: + return actor.category + @staticmethod def price_for(obj) -> float: """ diff --git a/src/holon/tests/test_costs_table.py b/src/holon/tests/test_costs_table.py index 9b69f57b5..e5e2e1b30 100644 --- a/src/holon/tests/test_costs_table.py +++ b/src/holon/tests/test_costs_table.py @@ -9,11 +9,10 @@ class CostTableTestClass(TestCase): def test_table_totals(self): """Test if the totals table is correctly set up""" scenario = Scenario.objects.get(pk=1) - costs_table = CostsTable.from_al_output(self.__al_output, scenario) + costs_table = CostsTable.from_al_output(self.__al_output(), scenario) - assert "CONNECTIONOWNER" in costs_table.keys - assert False - self.assertEqual(False, True) + assert "Bedrijventerrein HOLON" in costs_table.table.keys() + assert "CONNECTIONOWNER" in costs_table.table.keys() def __al_output(self): return [ From c072511cbcae0718b88e109e565070a5aedd5c29 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Fri, 7 Apr 2023 15:03:28 +0000 Subject: [PATCH 05/29] implements generic ETM query statements --- .../0035_genericetmquery_etmquery_generic.py | 40 +++++++++++++++++++ .../0036_remove_etmquery_generic.py | 16 ++++++++ ...nvertconfig_related_interactive_element.py | 21 ++++++++++ ...queryandconvertconfig_generic_etm_query.py | 17 ++++++++ .../0039_alter_etmquery_related_config.py | 28 +++++++++++++ .../models/config/datamodel_conversion.py | 3 +- src/holon/models/config/etm_query.py | 14 ++++++- src/holon/models/config/query_and_convert.py | 6 +++ 8 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 src/holon/migrations/0035_genericetmquery_etmquery_generic.py create mode 100644 src/holon/migrations/0036_remove_etmquery_generic.py create mode 100644 src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py create mode 100644 src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py create mode 100644 src/holon/migrations/0039_alter_etmquery_related_config.py diff --git a/src/holon/migrations/0035_genericetmquery_etmquery_generic.py b/src/holon/migrations/0035_genericetmquery_etmquery_generic.py new file mode 100644 index 000000000..cb22373d1 --- /dev/null +++ b/src/holon/migrations/0035_genericetmquery_etmquery_generic.py @@ -0,0 +1,40 @@ +# Generated by Django 4.1.7 on 2023-04-07 14:50 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0034_alter_etmquery_interactive_upscaling_comment_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="GenericETMQuery", + fields=[ + ( + "etmquery_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="holon.etmquery", + ), + ), + ], + options={ + "abstract": False, + }, + bases=("holon.etmquery",), + ), + migrations.AddField( + model_name="etmquery", + name="generic", + field=models.BooleanField( + default=False, verbose_name="Generic ETM query snippet" + ), + ), + ] diff --git a/src/holon/migrations/0036_remove_etmquery_generic.py b/src/holon/migrations/0036_remove_etmquery_generic.py new file mode 100644 index 000000000..bfa61975f --- /dev/null +++ b/src/holon/migrations/0036_remove_etmquery_generic.py @@ -0,0 +1,16 @@ +# Generated by Django 4.1.7 on 2023-04-07 14:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0035_genericetmquery_etmquery_generic"), + ] + + operations = [ + migrations.RemoveField( + model_name="etmquery", + name="generic", + ), + ] diff --git a/src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py b/src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py new file mode 100644 index 000000000..95371ee00 --- /dev/null +++ b/src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py @@ -0,0 +1,21 @@ +# Generated by Django 4.1.7 on 2023-04-07 14:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0036_remove_etmquery_generic"), + ] + + operations = [ + migrations.AddField( + model_name="queryandconvertconfig", + name="related_interactive_element", + field=models.ManyToManyField( + blank=True, + help_text="Use this field to relate this module configuration to a generic ETM query.", + to="holon.genericetmquery", + ), + ), + ] diff --git a/src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py b/src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py new file mode 100644 index 000000000..e78885b0e --- /dev/null +++ b/src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.7 on 2023-04-07 15:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0037_queryandconvertconfig_related_interactive_element"), + ] + + operations = [ + migrations.RenameField( + model_name="queryandconvertconfig", + old_name="related_interactive_element", + new_name="generic_etm_query", + ), + ] diff --git a/src/holon/migrations/0039_alter_etmquery_related_config.py b/src/holon/migrations/0039_alter_etmquery_related_config.py new file mode 100644 index 000000000..cadbf06b1 --- /dev/null +++ b/src/holon/migrations/0039_alter_etmquery_related_config.py @@ -0,0 +1,28 @@ +# Generated by Django 4.1.7 on 2023-04-07 15:01 + +from django.db import migrations +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + dependencies = [ + ( + "holon", + "0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query", + ), + ] + + operations = [ + migrations.AlterField( + model_name="etmquery", + name="related_config", + field=modelcluster.fields.ParentalKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="etm_query", + to="holon.queryandconvertconfig", + ), + ), + ] diff --git a/src/holon/models/config/datamodel_conversion.py b/src/holon/models/config/datamodel_conversion.py index 1c00c91e9..b2b7591a6 100644 --- a/src/holon/models/config/datamodel_conversion.py +++ b/src/holon/models/config/datamodel_conversion.py @@ -1,9 +1,8 @@ from django.db import models -from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from django.utils.translation import gettext_lazy as _ from modelcluster.fields import ParentalKey from modelcluster.models import ClusterableModel - +from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from holon.models.config.etm_query import ETMQuery diff --git a/src/holon/models/config/etm_query.py b/src/holon/models/config/etm_query.py index 638b46e9c..a5bccae51 100644 --- a/src/holon/models/config/etm_query.py +++ b/src/holon/models/config/etm_query.py @@ -3,9 +3,9 @@ from modelcluster.fields import ParentalKey from modelcluster.models import ClusterableModel from wagtail.admin.edit_handlers import FieldPanel, InlinePanel +from wagtail.snippets.models import register_snippet from holon.models.config.query_and_convert import QueryAndConvertConfig -from main.blocks.rich_text_block import RichtextBlock class EndPoint(models.TextChoices): @@ -35,7 +35,9 @@ class ETMQuery(ClusterableModel): help_text=_("Key as defined in the ETM"), ) - related_config = ParentalKey(QueryAndConvertConfig, related_name="etm_query") + related_config = ParentalKey( + QueryAndConvertConfig, related_name="etm_query", blank=True, null=True + ) related_interactive_element = models.ForeignKey( "holon.InteractiveElement", @@ -97,3 +99,11 @@ def clean(self) -> None: # TODO validate the use of etm_keys? return super().clean() + + +@register_snippet +class GenericETMQuery(ETMQuery): + pass + + def __str__(self) -> str: + return f"{self.internal_key}" diff --git a/src/holon/models/config/query_and_convert.py b/src/holon/models/config/query_and_convert.py index 4cbd0ea59..84980b140 100644 --- a/src/holon/models/config/query_and_convert.py +++ b/src/holon/models/config/query_and_convert.py @@ -33,6 +33,11 @@ class QueryAndConvertConfig(ClusterableModel): "Use this field to explain the query in the front-end. This field is rendered next to the KPI selection radio (that toggles between local, intermediate and national level)" ), ) + generic_etm_query = models.ManyToManyField( + "holon.GenericETMQuery", + blank=True, + help_text=_("Use this field to relate this module configuration to a generic ETM query."), + ) panels = [ FieldPanel("name"), @@ -40,6 +45,7 @@ class QueryAndConvertConfig(ClusterableModel): FieldPanel("module"), FieldPanel("etm_scenario_id"), FieldPanel("interactive_upscaling_comment"), + FieldPanel("generic_etm_query"), InlinePanel( "etm_query", heading="Define your input and query statements here", From 44eee705c969180fbf71587c45bdf8216ecec6e1 Mon Sep 17 00:00:00 2001 From: noracato Date: Fri, 7 Apr 2023 17:07:29 +0200 Subject: [PATCH 06/29] Fill out table and use feedin prices for CostTable --- src/holon/services/costs_table.py | 24 +++++++++++++++++------- src/holon/tests/test_costs_table.py | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/holon/services/costs_table.py b/src/holon/services/costs_table.py index 50c2ee9c6..7d0d9faeb 100644 --- a/src/holon/services/costs_table.py +++ b/src/holon/services/costs_table.py @@ -15,6 +15,7 @@ def table(self, cost_items): self._table = {} for item in cost_items: self.__add_to_table(item) + self.__fill_out_table() def __add_to_table(self, item): """TODO: also work with subgroups""" @@ -34,16 +35,20 @@ def __add_to_group(self, item): def __add_from_group(self, item): """ Also needs to add self as None - --> are we sure like this we always have all the keys? - Probably in the output (as_totals) we need to rebuild the thing for all - the different groups to be present + TODO: move some functionality from fill_out_table here """ - self._table[item.from_group()] = { item.to_group(): item.price, item.from_group(): None, } + def __fill_out_table(self): + # we can also keep a global set in memory (self) where we add to in __add_from_group + all_groups = set((key for value in self.table.values() for key in value.keys())) + basic = {key: 0.0 for key in all_groups} + for group in all_groups: + self._table[group] = basic | self._table.get(group, {}) + def as_totals(self): """TODO: returns the main groups view""" @@ -106,14 +111,19 @@ def price_for(obj) -> float: """ return ( obj.get("FinancialTransactionVolume_eur", 0.0) - + CostItem.delivery_price(obj) + + CostItem.delivery_or_feedin_price(obj) + obj.get("annualFee_eur", 0.0) ) @staticmethod - def delivery_price(obj) -> float: + def delivery_or_feedin_price(obj) -> float: """Check for the delivery price. If no prices sets defaults to 0""" - return obj.get("EnergyTransactionVolume_kWh", 0.0) * ( + volume = obj.get("EnergyTransactionVolume_kWh", 0.0) + if volume < 0: + return volume * ( + obj.get("feedinTax_eurpkWh", 0.0) + obj.get("feedinPrice_eurpkWh", 0.0) + ) + return volume * ( obj.get("deliveryTax_eurpkWh", 0.0) + obj.get("deliveryPrice_eurpkWh", 0.0) ) diff --git a/src/holon/tests/test_costs_table.py b/src/holon/tests/test_costs_table.py index e5e2e1b30..d40867b5b 100644 --- a/src/holon/tests/test_costs_table.py +++ b/src/holon/tests/test_costs_table.py @@ -13,6 +13,7 @@ def test_table_totals(self): assert "Bedrijventerrein HOLON" in costs_table.table.keys() assert "CONNECTIONOWNER" in costs_table.table.keys() + assert "OPERATORGRID" in costs_table.table.keys() def __al_output(self): return [ From feb00dff6d7b86d3db1016c94c52d94cb7fd4318 Mon Sep 17 00:00:00 2001 From: noracato Date: Fri, 21 Apr 2023 14:24:32 +0200 Subject: [PATCH 07/29] Add subgroups detailed view to CostTables and integrate in holon view --- src/holon/scripts/costbenefit.py | 16 --- src/holon/services/__init__.py | 1 + src/holon/services/costbenefit.py | 120 ------------------ src/holon/services/costs_table.py | 83 +++++++++--- .../merged-datamodel-ehub-config-fixture.json | 38 ++++-- src/holon/tests/test_costs_table.py | 19 ++- src/holon/views/holon.py | 12 +- 7 files changed, 110 insertions(+), 179 deletions(-) delete mode 100644 src/holon/scripts/costbenefit.py delete mode 100644 src/holon/services/costbenefit.py diff --git a/src/holon/scripts/costbenefit.py b/src/holon/scripts/costbenefit.py deleted file mode 100644 index cbce287a2..000000000 --- a/src/holon/scripts/costbenefit.py +++ /dev/null @@ -1,16 +0,0 @@ -def run(): - import json - from pathlib import Path - from holon.services import CostBenedict - - fp = Path(__file__).parent / "fixtures" / "outputs-anylogic-holon.json" - - with open(fp, "r") as infile: - outcomes = json.load(infile) - - actors: dict = outcomes["actors"] - - def dprint(d: dict) -> None: - print(json.dumps(d, indent=2)) - - dprint(CostBenedict(actors=actors).determine_group_costs()) diff --git a/src/holon/services/__init__.py b/src/holon/services/__init__.py index 9b557249b..dd762dfd4 100644 --- a/src/holon/services/__init__.py +++ b/src/holon/services/__init__.py @@ -2,3 +2,4 @@ from .costbenefit import * # noqa from .data import * # noqa from .query_and_convert import * # noqa +from .costs_table import CostTables diff --git a/src/holon/services/costbenefit.py b/src/holon/services/costbenefit.py deleted file mode 100644 index 57867205f..000000000 --- a/src/holon/services/costbenefit.py +++ /dev/null @@ -1,120 +0,0 @@ -# start class script -import json -from functools import partial -from typing import Union - - -def dprint(d: dict) -> None: - print(json.dumps(d, indent=2)) - - -class CostBenedict: - """it's not the egg it claims to be""" - - ## HARDCODED for now ;) - WANT_TO_KNOW = { - "Energieleverancier": "balanceElectricityDelivery_eur", - "Netbeheerder": "balanceElectricityTransport_eur", - "Overheid": "balanceElectricityTax_eur", - } - # not existing key; just for fun (only the slash is meaningful for later use) - NEK = "h4ck3rm4n69_was_here/" - - def __init__(self, actors: list) -> None: - self.actors = actors - - self.want_to_know = self.WANT_TO_KNOW - - # update the want to know with the holon actor group name (nice name) and a key - # that we are very sure of that it does not exist ;) - for actor in actors: - if "hol" in actor["actorID"]: - self.want_to_know.update({actor["group"]: self.NEK + actor["actorID"]}) - - def determine_group_costs(self): - return self.determine_cost(groupby="group", want_to_know=self.want_to_know) - - def determine_cost(self, groupby: str, want_to_know: dict): - direct_transactions = {} - groups = set() - for actor in self.actors: - if actor[groupby]: - groups.add(actor[groupby]) - - for group in groups: - filter_on_groupby = partial(self.filter_on_key, key=groupby, value=group) - group_members = list(filter(filter_on_groupby, self.actors)) - - direct_transactions.update( - self.sum_values(group=group, group_members=group_members, want_to_know=want_to_know) - ) - - ## This can be implemented cleverly with filters and maps I think, but not now - # obtain inverse transactions - inverse_transactions = {} - for party, transactions in direct_transactions.items(): - for receiving_party, value in transactions.items(): - try: - inverse_transactions[receiving_party][party] - except KeyError: - try: - inverse_transactions[receiving_party] - inverse_transactions[receiving_party].update({party: 0}) - except KeyError: - inverse_transactions.update({receiving_party: {}}) - inverse_transactions[receiving_party].update({party: 0}) - finally: - inverse_transactions[receiving_party][party] -= value - - # merge dicts - for party, transactions in inverse_transactions.items(): - try: - direct_transactions[party].update(transactions) - except KeyError: - direct_transactions.update({party: {}}) - direct_transactions[party].update(transactions) - - # round all transactions - for party, transactions in direct_transactions.items(): - for party, transaction in transactions.items(): - transactions[party] = round(transaction) - - # sort to make sure we give the front end the same order always - return dict(sorted(direct_transactions.items())) - - @staticmethod - def filter_on_key(dicto: dict, key: str = None, value: Union[str, float, int] = None) -> bool: - if dicto[key] == value: - return True - else: - return False - - def sum_values(self, group: str, group_members: list, want_to_know: dict) -> dict: - """based on the configuration sum differently""" - # TODO assumes based on parentholon property (acutally quite a nice solution) - - group_sum = {key: 0 for key in want_to_know.keys()} - - for member in group_members: - if member["parentHolon"] is not None: - for key in group_sum.keys(): - try: - holon_id = want_to_know[key].split("/")[1] - if member["parentHolon"] == holon_id: - group_sum[key] += sum( - [ - float(member[value]) if self.NEK not in value else 0 - for value in want_to_know.values() - ] - ) - except IndexError: - pass - - else: - for key in group_sum.keys(): - try: - group_sum[key] += float(member[want_to_know[key]]) - except KeyError: - pass - - return {group: group_sum} diff --git a/src/holon/services/costs_table.py b/src/holon/services/costs_table.py index 7d0d9faeb..79758d7cd 100644 --- a/src/holon/services/costs_table.py +++ b/src/holon/services/costs_table.py @@ -1,9 +1,37 @@ """Create a Costs&Benefits Table """ -class CostsTable: - def __init__(self, cost_items) -> None: - """cost_items is a generator of CostItems""" +class CostTables: + def __init__(self, cost_items: list) -> None: + """cost_items is a list of CostItems, we now loop it a lot - can that be improved?""" + self.cost_items = cost_items + + def main_table(self) -> dict: + return CostTable(self.cost_items).table + + def detailed_table(self, group) -> dict: + return CostTable(self.cost_items, use_subgroup=group).table + + def groups_for_detailed(self) -> set: + return set((group for item in self.cost_items for group in item.with_subgroups())) + + def all_detailed_tables(self) -> dict: + """ + Returns a dict where the keys are the applicable actor groups + and the values are their detailed tables + """ + return {group: self.detailed_table(group) for group in self.groups_for_detailed()} + + @classmethod + def from_al_output(cls, al_output, scenario): + actors = ActorWrapper.from_scenario(scenario) + return cls([CostItem.from_dict(item, actors) for item in al_output]) + + +class CostTable: + def __init__(self, cost_items, use_subgroup=None) -> None: + """cost_items is a list of CostItems""" + self._use_subgroup = use_subgroup self.table = cost_items @property @@ -18,9 +46,9 @@ def table(self, cost_items): self.__fill_out_table() def __add_to_table(self, item): - """TODO: also work with subgroups""" + """Adds the item to the table""" try: - self._table[item.from_group()][item.to_group()] += item.price + self._table[self.__name_from(item)][self.__name_to(item)] += item.price except KeyError: self.__add_from_group(item) except TypeError: @@ -28,7 +56,7 @@ def __add_to_table(self, item): def __add_to_group(self, item): try: - self._table[item.from_group()][item.to_group()] = item.price + self._table[self.__name_from(item)][self.__name_to(item)] = item.price except KeyError: self.__add_from_group(item) @@ -37,9 +65,9 @@ def __add_from_group(self, item): Also needs to add self as None TODO: move some functionality from fill_out_table here """ - self._table[item.from_group()] = { - item.to_group(): item.price, - item.from_group(): None, + self._table[self.__name_from(item)] = { + self.__name_to(item): item.price, + self.__name_from(item): None, } def __fill_out_table(self): @@ -49,16 +77,13 @@ def __fill_out_table(self): for group in all_groups: self._table[group] = basic | self._table.get(group, {}) - def as_totals(self): - """TODO: returns the main groups view""" - - def as_detailed_view(self, group): - """TODO: returns detailed view for the group""" + def __name_from(self, item): + return ( + item.from_subgroup() if self._use_subgroup == item.from_group() else item.from_group() + ) - @classmethod - def from_al_output(cls, al_output, scenario): - actors = ActorWrapper.from_scenario(scenario) - return cls((CostItem.from_dict(item, actors) for item in al_output)) + def __name_to(self, item): + return item.to_subgroup() if self._use_subgroup == item.to_group() else item.to_group() class ActorWrapper: @@ -69,7 +94,6 @@ def __init__(self, actors) -> None: def find(self, actor_name): """ Strips the AL prefix from the actor name and returns the corresponding Actor - TODO: Validate: does this actor exists -> what do we do if not """ return self.actors.get(id=int(actor_name[3:])) @@ -92,6 +116,19 @@ def from_group(self): def to_group(self): return CostItem.group(self.to_actor) + def from_subgroup(self): + return CostItem.subgroup(self.from_actor) + + def to_subgroup(self): + return CostItem.subgroup(self.to_actor) + + def with_subgroups(self): + """Returns groups that are connected to a subgroup""" + if self.from_actor.subgroup: + yield self.from_group() + if self.to_actor.subgroup: + yield self.to_group() + @staticmethod def group(actor): """Fallback to category if group is not defined""" @@ -100,6 +137,14 @@ def group(actor): except AttributeError: return actor.category + @staticmethod + def subgroup(actor): + """Fallback to group if subgroup is not defined""" + try: + return f"{CostItem.group(actor)} - {actor.subgroup.name}" + except AttributeError: + return CostItem.group(actor) + @staticmethod def price_for(obj) -> float: """ diff --git a/src/holon/tests/fixtures/merged-datamodel-ehub-config-fixture.json b/src/holon/tests/fixtures/merged-datamodel-ehub-config-fixture.json index 04b464f24..4f1786867 100644 --- a/src/holon/tests/fixtures/merged-datamodel-ehub-config-fixture.json +++ b/src/holon/tests/fixtures/merged-datamodel-ehub-config-fixture.json @@ -50,6 +50,13 @@ "name": "poor" } }, + { + "model": "holon.actorsubgroup", + "pk": 2, + "fields": { + "name": "rich" + } + }, { "model": "holon.actor", "pk": 1, @@ -134,13 +141,25 @@ "category": "CONNECTIONOWNER", "payload": 1, "group": 2, - "subgroup": null, + "subgroup": 1, "wildcard_JSON": null } }, { "model": "holon.actor", "pk": 8, + "fields": { + "polymorphic_ctype": ["holon", "actor"], + "category": "CONNECTIONOWNER", + "payload": 1, + "group": 2, + "subgroup": 2, + "wildcard_JSON": null + } + }, + { + "model": "holon.actor", + "pk": 9, "fields": { "polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", @@ -152,7 +171,7 @@ }, { "model": "holon.actor", - "pk": 9, + "pk": 10, "fields": { "polymorphic_ctype": ["holon", "actor"], "category": "GOVHOLON", @@ -2182,8 +2201,7 @@ "data_type": "value", "etm_key": "capacity_of_energy_power_wind_turbine_inland", "related_config": 1, - "related_interactive_element": null, - "interactive_upscaling_comment": null + "related_interactive_element": null } }, { @@ -2195,8 +2213,7 @@ "data_type": "value", "etm_key": "price_of_natural_gas_per_mwh", "related_config": 2, - "related_interactive_element": null, - "interactive_upscaling_comment": null + "related_interactive_element": null } }, { @@ -2208,8 +2225,7 @@ "data_type": "value", "etm_key": "capacity_of_energy_power_wind_turbine_inland", "related_config": 3, - "related_interactive_element": null, - "interactive_upscaling_comment": null + "related_interactive_element": null } }, { @@ -2221,8 +2237,7 @@ "data_type": "value", "etm_key": "tester_etm_key", "related_config": 4, - "related_interactive_element": null, - "interactive_upscaling_comment": null + "related_interactive_element": null } }, { @@ -2234,8 +2249,7 @@ "data_type": "curve", "etm_key": "hourly_price_of_electricity_per_mwh", "related_config": 2, - "related_interactive_element": null, - "interactive_upscaling_comment": null + "related_interactive_element": null } }, { diff --git a/src/holon/tests/test_costs_table.py b/src/holon/tests/test_costs_table.py index d40867b5b..14e0c3c40 100644 --- a/src/holon/tests/test_costs_table.py +++ b/src/holon/tests/test_costs_table.py @@ -1,6 +1,6 @@ from django.test import TestCase from holon.models.scenario import Scenario -from holon.services.costs_table import CostsTable +from holon.services.costs_table import CostTables class CostTableTestClass(TestCase): @@ -9,11 +9,20 @@ class CostTableTestClass(TestCase): def test_table_totals(self): """Test if the totals table is correctly set up""" scenario = Scenario.objects.get(pk=1) - costs_table = CostsTable.from_al_output(self.__al_output(), scenario) + tables = CostTables.from_al_output(self.__al_output(), scenario) + costs_table = tables.main_table() - assert "Bedrijventerrein HOLON" in costs_table.table.keys() - assert "CONNECTIONOWNER" in costs_table.table.keys() - assert "OPERATORGRID" in costs_table.table.keys() + assert "Bedrijventerrein HOLON" in costs_table.keys() + assert "CONNECTIONOWNER" in costs_table.keys() + assert "OPERATORGRID" in costs_table.keys() + + detailed_table = tables.detailed_table("Commercieel bedrijf 1") + assert "Commercieel bedrijf 1 - poor" in detailed_table.keys() + assert "Commercieel bedrijf 1 - rich" in detailed_table.keys() + + detailed_tables = tables.all_detailed_tables() + assert "Commercieel bedrijf 1" in detailed_tables.keys() + assert "Commercieel bedrijf 2" not in detailed_tables.keys() def __al_output(self): return [ diff --git a/src/holon/views/holon.py b/src/holon/views/holon.py index fa8f0b3d6..eb0268703 100644 --- a/src/holon/views/holon.py +++ b/src/holon/views/holon.py @@ -9,7 +9,7 @@ from holon.models.scenario_rule import ModelType from holon.models.util import all_subclasses, is_exclude_field from holon.serializers import HolonRequestSerializer, ScenarioSerializer -from holon.services import CostBenedict, ETMConnect +from holon.services import CostTables, ETMConnect from holon.services.cloudclient import CloudClient from holon.services.data import Results @@ -59,18 +59,16 @@ def post(self, request: Request): elif name == "Regional upscaling": etm_outcomes["inter_upscaling_outcomes"] = outcome - pprint("Running CostBenedict module") + pprint("Calculating CostTables") # ignore me! (TODO: should only be triggered on bedrijventerrein) - cost_benefit_results = CostBenedict( - actors=cc.outputs["actors"] - ).determine_group_costs() + cost_benefit_tables = CostTables.from_al_output(cc.outputs["actors"], scenario) results = Results( scenario=scenario, request=request, anylogic_outcomes=cc.outputs, - cost_benefit_detail=cost_benefit_results, # TODO: twice the same! - cost_benefit_overview=cost_benefit_results, # TODO: twice the same! + cost_benefit_results=cost_benefit_tables.main_table(), + cost_benefit_overview=cost_benefit_tables.all_detailed_tables(), **etm_outcomes, ) From db6a6873e2e65a92a92c0a8821c2321169d77251 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Fri, 21 Apr 2023 13:03:22 +0000 Subject: [PATCH 08/29] add genericETMqueries --- src/holon/services/query_and_convert.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/holon/services/query_and_convert.py b/src/holon/services/query_and_convert.py index c9f2a3baf..01a4c3790 100644 --- a/src/holon/services/query_and_convert.py +++ b/src/holon/services/query_and_convert.py @@ -1,9 +1,13 @@ +<<<<<<< HEAD from copy import deepcopy as copy +======= +>>>>>>> 778e187 (add genericETMqueries) from typing import List import etm_service from holon.models import DatamodelQueryRule, Scenario +<<<<<<< HEAD from holon.models.config import ( AnyLogicConversion, DatamodelConversion, @@ -14,6 +18,12 @@ QueryAndConvertConfig, StaticConversion, ) +======= +from holon.models.config import (AnyLogicConversion, DatamodelConversion, + ETMConversion, ETMQuery, GenericETMQuery, + KeyValuePairCollection, QueryAndConvertConfig, + StaticConversion) +>>>>>>> 778e187 (add genericETMqueries) def pprint(msg: str): @@ -130,6 +140,10 @@ def unpack_queries(self): self._queries["config"].update( Query(query=q, config=self, copied_scenario=self.copied_scenario).to_dict() ) + for q in GenericETMQuery.objects.get(id__in=self.config_db.generic_etm_query.prefetch_related('id').all().id): + self._queries["config"].update( + Query(query=q, config=self, copied_scenario=self.copied_scenario).to_dict() + ) class Query: From a61600641cda65dbf018a6b2ca9bd08281f1c4d1 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Fri, 21 Apr 2023 13:47:23 +0000 Subject: [PATCH 09/29] merge and add generic ETM queries --- src/holon/services/__init__.py | 3 +-- src/holon/services/query_and_convert.py | 18 +----------------- src/holon/views/holon.py | 3 +-- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/holon/services/__init__.py b/src/holon/services/__init__.py index dd762dfd4..a2f1b3692 100644 --- a/src/holon/services/__init__.py +++ b/src/holon/services/__init__.py @@ -1,5 +1,4 @@ from .cloudclient import * # noqa -from .costbenefit import * # noqa +from .costs_table import CostTables from .data import * # noqa from .query_and_convert import * # noqa -from .costs_table import CostTables diff --git a/src/holon/services/query_and_convert.py b/src/holon/services/query_and_convert.py index 01a4c3790..e0d7aedc6 100644 --- a/src/holon/services/query_and_convert.py +++ b/src/holon/services/query_and_convert.py @@ -1,29 +1,13 @@ -<<<<<<< HEAD from copy import deepcopy as copy -======= ->>>>>>> 778e187 (add genericETMqueries) from typing import List import etm_service from holon.models import DatamodelQueryRule, Scenario -<<<<<<< HEAD -from holon.models.config import ( - AnyLogicConversion, - DatamodelConversion, - ETMConversion, - ETMQuery, - FloatKeyValuePair, - KeyValuePairCollection, - QueryAndConvertConfig, - StaticConversion, -) -======= from holon.models.config import (AnyLogicConversion, DatamodelConversion, ETMConversion, ETMQuery, GenericETMQuery, KeyValuePairCollection, QueryAndConvertConfig, StaticConversion) ->>>>>>> 778e187 (add genericETMqueries) def pprint(msg: str): @@ -140,7 +124,7 @@ def unpack_queries(self): self._queries["config"].update( Query(query=q, config=self, copied_scenario=self.copied_scenario).to_dict() ) - for q in GenericETMQuery.objects.get(id__in=self.config_db.generic_etm_query.prefetch_related('id').all().id): + for q in self.config_db.generic_etm_query.all(): self._queries["config"].update( Query(query=q, config=self, copied_scenario=self.copied_scenario).to_dict() ) diff --git a/src/holon/views/holon.py b/src/holon/views/holon.py index eb0268703..2f0981ca2 100644 --- a/src/holon/views/holon.py +++ b/src/holon/views/holon.py @@ -60,8 +60,7 @@ def post(self, request: Request): etm_outcomes["inter_upscaling_outcomes"] = outcome pprint("Calculating CostTables") - # ignore me! (TODO: should only be triggered on bedrijventerrein) - cost_benefit_tables = CostTables.from_al_output(cc.outputs["actors"], scenario) + cost_benefit_tables = CostTables.from_al_output(cc.outputs["contracts"], scenario) results = Results( scenario=scenario, From a14003f591ba6ff795bd077fe27287e3f84cf2f4 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Mon, 24 Apr 2023 06:34:36 +0000 Subject: [PATCH 10/29] fix formatting --- src/holon/services/query_and_convert.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/holon/services/query_and_convert.py b/src/holon/services/query_and_convert.py index e0d7aedc6..787a52562 100644 --- a/src/holon/services/query_and_convert.py +++ b/src/holon/services/query_and_convert.py @@ -4,10 +4,16 @@ import etm_service from holon.models import DatamodelQueryRule, Scenario -from holon.models.config import (AnyLogicConversion, DatamodelConversion, - ETMConversion, ETMQuery, GenericETMQuery, - KeyValuePairCollection, QueryAndConvertConfig, - StaticConversion) +from holon.models.config import ( + AnyLogicConversion, + DatamodelConversion, + ETMConversion, + ETMQuery, + GenericETMQuery, + KeyValuePairCollection, + QueryAndConvertConfig, + StaticConversion, +) def pprint(msg: str): From e8ac1901c7791be53282c5501f453681d38d5ad3 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Mon, 24 Apr 2023 09:11:50 +0000 Subject: [PATCH 11/29] Implement try and catch block to ensure that we always get contracts (include raw results) --- .../migrations/0040_merge_20230424_0846.py | 12 ++++++++++ src/holon/services/cloudclient/client.py | 5 +++- src/holon/services/query_and_convert.py | 2 +- src/holon/views/holon.py | 23 ++++++++++++++++--- 4 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 src/holon/migrations/0040_merge_20230424_0846.py diff --git a/src/holon/migrations/0040_merge_20230424_0846.py b/src/holon/migrations/0040_merge_20230424_0846.py new file mode 100644 index 000000000..b0118829b --- /dev/null +++ b/src/holon/migrations/0040_merge_20230424_0846.py @@ -0,0 +1,12 @@ +# Generated by Django 4.1.8 on 2023-04-24 06:46 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0037_alter_contract_actor_alter_contract_contractscope"), + ("holon", "0039_alter_etmquery_related_config"), + ] + + operations = [] diff --git a/src/holon/services/cloudclient/client.py b/src/holon/services/cloudclient/client.py index 3171f51b0..a47c9df6f 100644 --- a/src/holon/services/cloudclient/client.py +++ b/src/holon/services/cloudclient/client.py @@ -1,6 +1,7 @@ import json -from anylogiccloudclient.client.cloud_client import CloudClient as ALCloudClient +from anylogiccloudclient.client.cloud_client import \ + CloudClient as ALCloudClient from anylogiccloudclient.client.cloud_client import Inputs from anylogiccloudclient.client.single_run_outputs import SingleRunOutputs @@ -93,3 +94,5 @@ def outputs(self, anylogic_outputs: SingleRunOutputs): co.internal_key: json.loads(anylogic_outputs.value(co.anylogic_key)) for co in self.config.anylogic_cloud_output.all() } + # store raw results + self._outputs_raw = {name: anylogic_outputs.value(name) for name in anylogic_outputs.names()} diff --git a/src/holon/services/query_and_convert.py b/src/holon/services/query_and_convert.py index 787a52562..b44cf5c8b 100644 --- a/src/holon/services/query_and_convert.py +++ b/src/holon/services/query_and_convert.py @@ -20,7 +20,7 @@ def pprint(msg: str): print(f"[QConfig]: {msg}") -# I'm very sorry for this... or was it somewhere I could not find it? +# Hardcoded because not bound to change at any point during this project CONFIG_KPIS = { "api_url": "https://beta-engine.energytransitionmodel.com/api/v3/scenarios/", "config": { diff --git a/src/holon/views/holon.py b/src/holon/views/holon.py index 2f0981ca2..5f9f8184d 100644 --- a/src/holon/views/holon.py +++ b/src/holon/views/holon.py @@ -1,3 +1,4 @@ +import json import traceback from django.apps import apps @@ -60,14 +61,30 @@ def post(self, request: Request): etm_outcomes["inter_upscaling_outcomes"] = outcome pprint("Calculating CostTables") - cost_benefit_tables = CostTables.from_al_output(cc.outputs["contracts"], scenario) + try: + cost_benefit_tables = CostTables.from_al_output( + cc.outputs["contracts"], scenario + ) + except KeyError: + pprint("contract data is not mapped, trying to find the correct output...") + found = False + for key, alternative_output in cc._outputs_raw.items(): + if "contract" in key: + found = True + pprint("...success!") + cost_benefit_tables = CostTables.from_al_output( + json.loads(alternative_output), scenario + ) + break + if not found: + raise KeyError results = Results( scenario=scenario, request=request, anylogic_outcomes=cc.outputs, - cost_benefit_results=cost_benefit_tables.main_table(), - cost_benefit_overview=cost_benefit_tables.all_detailed_tables(), + cost_benefit_overview=cost_benefit_tables.main_table(), + cost_benefit_detail=cost_benefit_tables.all_detailed_tables(), **etm_outcomes, ) From c53c60e7ea4862d2417e75d808114ad571933f65 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Mon, 24 Apr 2023 10:07:54 +0000 Subject: [PATCH 12/29] formatting and removing unused modules --- src/holon/models/config/query_and_convert.py | 2 -- src/holon/services/cloudclient/client.py | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/holon/models/config/query_and_convert.py b/src/holon/models/config/query_and_convert.py index 84980b140..100caf8e6 100644 --- a/src/holon/models/config/query_and_convert.py +++ b/src/holon/models/config/query_and_convert.py @@ -5,7 +5,6 @@ from wagtail.admin.edit_handlers import FieldPanel, InlinePanel from holon.models.scenario import Scenario -from main.blocks.rich_text_block import RichtextBlock class QueryCovertModuleType(models.TextChoices): @@ -50,7 +49,6 @@ class QueryAndConvertConfig(ClusterableModel): "etm_query", heading="Define your input and query statements here", label="ETM query/input statement", - min_num=1, ), InlinePanel( "key_value_pair_collection", diff --git a/src/holon/services/cloudclient/client.py b/src/holon/services/cloudclient/client.py index a47c9df6f..041e76ac5 100644 --- a/src/holon/services/cloudclient/client.py +++ b/src/holon/services/cloudclient/client.py @@ -1,7 +1,6 @@ import json -from anylogiccloudclient.client.cloud_client import \ - CloudClient as ALCloudClient +from anylogiccloudclient.client.cloud_client import CloudClient as ALCloudClient from anylogiccloudclient.client.cloud_client import Inputs from anylogiccloudclient.client.single_run_outputs import SingleRunOutputs @@ -95,4 +94,6 @@ def outputs(self, anylogic_outputs: SingleRunOutputs): for co in self.config.anylogic_cloud_output.all() } # store raw results - self._outputs_raw = {name: anylogic_outputs.value(name) for name in anylogic_outputs.names()} + self._outputs_raw = { + name: anylogic_outputs.value(name) for name in anylogic_outputs.names() + } From 49f17a3277dad41f2b4a07565d44ec04980e88c7 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Mon, 24 Apr 2023 10:11:41 +0000 Subject: [PATCH 13/29] clean up migrations --- ...ry_interactive_upscaling_title_and_more.py | 45 --------- ..._interactive_upscaling_comment_and_more.py | 32 ------ .../0035_genericetmquery_etmquery_generic.py | 40 -------- .../0036_remove_etmquery_generic.py | 16 --- ...nvertconfig_related_interactive_element.py | 21 ---- ...ry_interactive_upscaling_title_and_more.py | 97 +++++++++++++++++++ ...queryandconvertconfig_generic_etm_query.py | 17 ---- .../0039_alter_etmquery_related_config.py | 28 ------ .../migrations/0040_merge_20230424_0846.py | 12 --- 9 files changed, 97 insertions(+), 211 deletions(-) delete mode 100644 src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py delete mode 100644 src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py delete mode 100644 src/holon/migrations/0035_genericetmquery_etmquery_generic.py delete mode 100644 src/holon/migrations/0036_remove_etmquery_generic.py delete mode 100644 src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py create mode 100644 src/holon/migrations/0038_genericetmquery_etmquery_interactive_upscaling_title_and_more.py delete mode 100644 src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py delete mode 100644 src/holon/migrations/0039_alter_etmquery_related_config.py delete mode 100644 src/holon/migrations/0040_merge_20230424_0846.py diff --git a/src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py b/src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py deleted file mode 100644 index 2f2b878c9..000000000 --- a/src/holon/migrations/0033_etmquery_interactive_upscaling_title_and_more.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 12:54 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0032_merge_20230406_1342"), - ] - - operations = [ - migrations.AddField( - model_name="etmquery", - name="interactive_upscaling_title", - field=models.CharField( - blank=True, - help_text="Title of the explaination of upscaling. For instance, the category of the upscaling component ('Zon op dak').", - max_length=255, - null=True, - ), - ), - migrations.AddField( - model_name="queryandconvertconfig", - name="interactive_upscaling_comment", - field=models.CharField( - blank=True, - help_text="Use this field to explain the query in the front-end. This field is rendered next to the KPI selection radio (that toggles between local, intermediate and national level)", - max_length=255, - null=True, - ), - ), - migrations.AlterField( - model_name="queryandconvertconfig", - name="module", - field=models.CharField( - choices=[ - ("upscaling", "Upscaling"), - ("upscaling-regional", "Upscaling Regional"), - ("cost", "Cost"), - ("costbenefit", "Costbenefit"), - ], - max_length=255, - ), - ), - ] diff --git a/src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py b/src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py deleted file mode 100644 index 071bf81da..000000000 --- a/src/holon/migrations/0034_alter_etmquery_interactive_upscaling_comment_and_more.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 12:56 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0033_etmquery_interactive_upscaling_title_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="etmquery", - name="interactive_upscaling_comment", - field=models.TextField( - blank=True, - help_text="Use this field to explain the query in the front-end. Use {{variable}} for dynamic values. Options: local key-value pairs e.g., `scaling_factor`, `final_value` or `query_value` (to be implemented)", - max_length=255, - null=True, - ), - ), - migrations.AlterField( - model_name="queryandconvertconfig", - name="interactive_upscaling_comment", - field=models.TextField( - blank=True, - help_text="Use this field to explain the query in the front-end. This field is rendered next to the KPI selection radio (that toggles between local, intermediate and national level)", - max_length=255, - null=True, - ), - ), - ] diff --git a/src/holon/migrations/0035_genericetmquery_etmquery_generic.py b/src/holon/migrations/0035_genericetmquery_etmquery_generic.py deleted file mode 100644 index cb22373d1..000000000 --- a/src/holon/migrations/0035_genericetmquery_etmquery_generic.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 14:50 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0034_alter_etmquery_interactive_upscaling_comment_and_more"), - ] - - operations = [ - migrations.CreateModel( - name="GenericETMQuery", - fields=[ - ( - "etmquery_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="holon.etmquery", - ), - ), - ], - options={ - "abstract": False, - }, - bases=("holon.etmquery",), - ), - migrations.AddField( - model_name="etmquery", - name="generic", - field=models.BooleanField( - default=False, verbose_name="Generic ETM query snippet" - ), - ), - ] diff --git a/src/holon/migrations/0036_remove_etmquery_generic.py b/src/holon/migrations/0036_remove_etmquery_generic.py deleted file mode 100644 index bfa61975f..000000000 --- a/src/holon/migrations/0036_remove_etmquery_generic.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 14:53 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0035_genericetmquery_etmquery_generic"), - ] - - operations = [ - migrations.RemoveField( - model_name="etmquery", - name="generic", - ), - ] diff --git a/src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py b/src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py deleted file mode 100644 index 95371ee00..000000000 --- a/src/holon/migrations/0037_queryandconvertconfig_related_interactive_element.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 14:56 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0036_remove_etmquery_generic"), - ] - - operations = [ - migrations.AddField( - model_name="queryandconvertconfig", - name="related_interactive_element", - field=models.ManyToManyField( - blank=True, - help_text="Use this field to relate this module configuration to a generic ETM query.", - to="holon.genericetmquery", - ), - ), - ] diff --git a/src/holon/migrations/0038_genericetmquery_etmquery_interactive_upscaling_title_and_more.py b/src/holon/migrations/0038_genericetmquery_etmquery_interactive_upscaling_title_and_more.py new file mode 100644 index 000000000..08f0a0fe9 --- /dev/null +++ b/src/holon/migrations/0038_genericetmquery_etmquery_interactive_upscaling_title_and_more.py @@ -0,0 +1,97 @@ +# Generated by Django 4.1.8 on 2023-04-24 10:11 + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0037_alter_contract_actor_alter_contract_contractscope"), + ] + + operations = [ + migrations.CreateModel( + name="GenericETMQuery", + fields=[ + ( + "etmquery_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="holon.etmquery", + ), + ), + ], + options={ + "abstract": False, + }, + bases=("holon.etmquery",), + ), + migrations.AddField( + model_name="etmquery", + name="interactive_upscaling_title", + field=models.CharField( + blank=True, + help_text="Title of the explaination of upscaling. For instance, the category of the upscaling component ('Zon op dak').", + max_length=255, + null=True, + ), + ), + migrations.AddField( + model_name="queryandconvertconfig", + name="interactive_upscaling_comment", + field=models.TextField( + blank=True, + help_text="Use this field to explain the query in the front-end. This field is rendered next to the KPI selection radio (that toggles between local, intermediate and national level)", + max_length=255, + null=True, + ), + ), + migrations.AlterField( + model_name="etmquery", + name="interactive_upscaling_comment", + field=models.TextField( + blank=True, + help_text="Use this field to explain the query in the front-end. Use {{variable}} for dynamic values. Options: local key-value pairs e.g., `scaling_factor`, `final_value` or `query_value` (to be implemented)", + max_length=255, + null=True, + ), + ), + migrations.AlterField( + model_name="etmquery", + name="related_config", + field=modelcluster.fields.ParentalKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="etm_query", + to="holon.queryandconvertconfig", + ), + ), + migrations.AlterField( + model_name="queryandconvertconfig", + name="module", + field=models.CharField( + choices=[ + ("upscaling", "Upscaling"), + ("upscaling-regional", "Upscaling Regional"), + ("cost", "Cost"), + ("costbenefit", "Costbenefit"), + ], + max_length=255, + ), + ), + migrations.AddField( + model_name="queryandconvertconfig", + name="generic_etm_query", + field=models.ManyToManyField( + blank=True, + help_text="Use this field to relate this module configuration to a generic ETM query.", + to="holon.genericetmquery", + ), + ), + ] diff --git a/src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py b/src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py deleted file mode 100644 index e78885b0e..000000000 --- a/src/holon/migrations/0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 15:00 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0037_queryandconvertconfig_related_interactive_element"), - ] - - operations = [ - migrations.RenameField( - model_name="queryandconvertconfig", - old_name="related_interactive_element", - new_name="generic_etm_query", - ), - ] diff --git a/src/holon/migrations/0039_alter_etmquery_related_config.py b/src/holon/migrations/0039_alter_etmquery_related_config.py deleted file mode 100644 index cadbf06b1..000000000 --- a/src/holon/migrations/0039_alter_etmquery_related_config.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 4.1.7 on 2023-04-07 15:01 - -from django.db import migrations -import django.db.models.deletion -import modelcluster.fields - - -class Migration(migrations.Migration): - dependencies = [ - ( - "holon", - "0038_rename_related_interactive_element_queryandconvertconfig_generic_etm_query", - ), - ] - - operations = [ - migrations.AlterField( - model_name="etmquery", - name="related_config", - field=modelcluster.fields.ParentalKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="etm_query", - to="holon.queryandconvertconfig", - ), - ), - ] diff --git a/src/holon/migrations/0040_merge_20230424_0846.py b/src/holon/migrations/0040_merge_20230424_0846.py deleted file mode 100644 index b0118829b..000000000 --- a/src/holon/migrations/0040_merge_20230424_0846.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 4.1.8 on 2023-04-24 06:46 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("holon", "0037_alter_contract_actor_alter_contract_contractscope"), - ("holon", "0039_alter_etmquery_related_config"), - ] - - operations = [] From 663e83c84ef42aae7291b75049a5511f64953d6d Mon Sep 17 00:00:00 2001 From: Mattijs Stam Date: Mon, 24 Apr 2023 13:26:22 +0000 Subject: [PATCH 14/29] Adds exception for InteractiveElementChooser outside of pages --- src/main/blocks/storyline_section.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/blocks/storyline_section.py b/src/main/blocks/storyline_section.py index 0bcf97484..a1e0bb72a 100644 --- a/src/main/blocks/storyline_section.py +++ b/src/main/blocks/storyline_section.py @@ -33,6 +33,12 @@ def get_queryset(self, request): from main.pages.casus import CasusPage qs = super().get_queryset(request) + + # Send all interactive elements as queryset if the interactive element is linked outside of the pages + if request.META.get("HTTP_REFERER").find("pages") == -1: + return qs + + casus_id = request.META.get("HTTP_REFERER").split("/")[-2] if casus_id == "edit": From a7ee27f62a727c88b0ff820cb306bc421763b580 Mon Sep 17 00:00:00 2001 From: Mattijs Stam Date: Mon, 24 Apr 2023 13:57:55 +0000 Subject: [PATCH 15/29] Fix formatting issues --- src/holon/models/filter.py | 1 - src/main/blocks/storyline_section.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/holon/models/filter.py b/src/holon/models/filter.py index a90b39717..c5f5e8dca 100644 --- a/src/holon/models/filter.py +++ b/src/holon/models/filter.py @@ -279,7 +279,6 @@ def second_order_relation_field_options(self) -> list[str]: ] def second_order_relation_field_subtype_options(self) -> list[str]: - related_model = get_relation_model( self.rule, self.relation_field, self.relation_field_subtype ) diff --git a/src/main/blocks/storyline_section.py b/src/main/blocks/storyline_section.py index a1e0bb72a..feab9eea3 100644 --- a/src/main/blocks/storyline_section.py +++ b/src/main/blocks/storyline_section.py @@ -33,12 +33,11 @@ def get_queryset(self, request): from main.pages.casus import CasusPage qs = super().get_queryset(request) - + # Send all interactive elements as queryset if the interactive element is linked outside of the pages if request.META.get("HTTP_REFERER").find("pages") == -1: return qs - casus_id = request.META.get("HTTP_REFERER").split("/")[-2] if casus_id == "edit": From 264c74b86df20c002a93a05c9c38fb492031a582 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Tue, 25 Apr 2023 14:29:27 +0000 Subject: [PATCH 16/29] Make sure that we don't overwrite existing entries with the try/except --- src/holon/services/costs_table.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/holon/services/costs_table.py b/src/holon/services/costs_table.py index 79758d7cd..0cd616979 100644 --- a/src/holon/services/costs_table.py +++ b/src/holon/services/costs_table.py @@ -49,9 +49,7 @@ def __add_to_table(self, item): """Adds the item to the table""" try: self._table[self.__name_from(item)][self.__name_to(item)] += item.price - except KeyError: - self.__add_from_group(item) - except TypeError: + except: self.__add_to_group(item) def __add_to_group(self, item): @@ -109,6 +107,7 @@ def __init__(self, to_actor, from_actor, price) -> None: self.from_actor = from_actor self.to_actor = to_actor self.price = price + print(f"CostItem: {self.from_group()} -> {self.to_group()} = {self.price}") def from_group(self): return CostItem.group(self.from_actor) From f7e1e573cebb13d1a595dc818b2e47ed81e5be1b Mon Sep 17 00:00:00 2001 From: Mattijs Stam Date: Mon, 24 Apr 2023 13:51:40 +0000 Subject: [PATCH 17/29] Fixes merge conflict --- src/main/blocks/storyline_section.py | 8 + ...er_challengemodepage_storyline_and_more.py | 2052 +++++++++++++++++ 2 files changed, 2060 insertions(+) create mode 100644 src/main/migrations/0064_alter_challengemodepage_storyline_and_more.py diff --git a/src/main/blocks/storyline_section.py b/src/main/blocks/storyline_section.py index feab9eea3..148094ac0 100644 --- a/src/main/blocks/storyline_section.py +++ b/src/main/blocks/storyline_section.py @@ -67,6 +67,10 @@ class InteractiveInputBlock(blocks.StructBlock): default_value = blocks.CharBlock( required=False, help_text="Type the default value exactly as it's shown on the website page" ) + target_value = blocks.CharBlock( + required=False, + help_text="Type a target value if this value needs to be added to the current and all underlying sections. Type the value exactly as it's shown on the website page. Seperate multiple values by a comma (no whitespaces)", + ) def get_api_representation(self, value, context=None): if value and value["interactive_input"] is not None: @@ -83,6 +87,9 @@ def get_api_representation(self, value, context=None): if bool(value["default_value"]): if value["default_value"].lower() == option.option.lower(): option_default = True + elif bool(value["target_value"]): + if value["target_value"].lower() == option.option.lower(): + option_default = True else: option_default = option.default option_dict = { @@ -128,6 +135,7 @@ def get_api_representation(self, value, context=None): "locked": value["locked"], "display": value["display"], "default_value_override": value["default_value"], + "target_value": value["target_value"], } if interactive_input.link_wiki_page is not None: diff --git a/src/main/migrations/0064_alter_challengemodepage_storyline_and_more.py b/src/main/migrations/0064_alter_challengemodepage_storyline_and_more.py new file mode 100644 index 000000000..660a0180a --- /dev/null +++ b/src/main/migrations/0064_alter_challengemodepage_storyline_and_more.py @@ -0,0 +1,2052 @@ +# Generated by Django 4.1.8 on 2023-04-24 13:32 + +from django.db import migrations +import main.blocks.holon_image_chooser +import main.blocks.legend_item +import main.blocks.page_chooser_block +import main.blocks.rich_text_block +import wagtail.blocks +import wagtail.embeds.blocks +import wagtail.fields +import wagtailmodelchooser.blocks + + +class Migration(migrations.Migration): + dependencies = [ + ("main", "0063_alter_challengemodepage_feedbackmodals_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="challengemodepage", + name="storyline", + field=wagtail.fields.StreamField( + [ + ( + "header_full_image_block", + wagtail.blocks.StructBlock( + [ + ("title", wagtail.blocks.CharBlock(required=True)), + ( + "size", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ("", "Select header size"), + ("h1", "H1"), + ("h2", "H2"), + ], + ), + ), + ( + "image_selector", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=True + ), + ), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Fill in this alt-text only when you want to describe the image (for screenreaders and SEO)", + required=False, + ), + ), + ] + ), + ), + ( + "text_and_media", + wagtail.blocks.StructBlock( + [ + ( + "grid_layout", + wagtail.blocks.StructBlock( + [ + ( + "grid", + wagtail.blocks.ChoiceBlock( + choices=[ + ("33_66", "33% - 66%"), + ("50_50", "50% - 50%"), + ("66_33", "66% - 33%"), + ] + ), + ) + ], + required=True, + ), + ), + ( + "column_order", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ("", "Default (Text left, Media right)"), + ( + "invert", + "Invert columns (Media left, Text right)", + ), + ], + required=False, + ), + ), + ( + "background", + wagtail.blocks.StructBlock( + [ + ( + "color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("block__bg-white", "White"), + ("block__bg-gray", "Pale gray"), + ( + "block__bg-purple", + "Pale purple", + ), + ] + ), + ), + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bg__full", + "Full backgroundcolor", + ), + ( + "bg__left", + "Only backgroundcolor in the left block", + ), + ] + ), + ), + ] + ), + ), + ( + "text", + main.blocks.rich_text_block.RichtextBlock( + help_text="Add your text", + required=True, + rows=15, + ), + ), + ( + "media", + wagtail.blocks.StreamBlock( + [ + ( + "image", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=False + ), + ), + ( + "video", + wagtail.embeds.blocks.EmbedBlock( + help_text="Youtube url of vimeo url", + required=False, + ), + ), + ], + help_text="Choose an image or paste an embed url", + max_num=1, + ), + ), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Fill in this alt-text only when you want to describe the image (for screenreaders and SEO)", + required=False, + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ( + "section", + wagtail.blocks.StructBlock( + [ + ( + "background", + wagtail.blocks.StructBlock( + [ + ( + "color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("block__bg-white", "White"), + ("block__bg-gray", "Pale gray"), + ( + "block__bg-purple", + "Pale purple", + ), + ] + ), + ), + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bg__full", + "Full backgroundcolor", + ), + ( + "bg__left", + "Only backgroundcolor in the left block", + ), + ] + ), + ), + ] + ), + ), + ( + "grid_layout", + wagtail.blocks.StructBlock( + [ + ( + "grid", + wagtail.blocks.ChoiceBlock( + choices=[ + ("33_66", "33% - 66%"), + ("50_50", "50% - 50%"), + ("66_33", "66% - 33%"), + ] + ), + ) + ], + required=True, + ), + ), + ( + "text_label_national", + wagtail.blocks.CharBlock( + default="Nationaal", required=True + ), + ), + ( + "text_label_intermediate", + wagtail.blocks.CharBlock( + default="Regionaal", required=True + ), + ), + ( + "text_label_local", + wagtail.blocks.CharBlock( + default="Lokaal", required=True + ), + ), + ( + "content", + wagtail.blocks.StreamBlock( + [ + ( + "text", + main.blocks.rich_text_block.RichtextBlock(), + ), + ( + "interactive_input", + wagtail.blocks.StructBlock( + [ + ( + "interactive_input", + wagtailmodelchooser.blocks.ModelChooserBlock( + help_text="Choose an Interactive Element of type `Single select` or `Continuous`", + target_model="holon.interactiveelement", + ), + ), + ( + "display", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "checkbox_radio", + "Show as checkboxe(s) or radiobutton(s)", + ), + ( + "dropdown", + "Show as dropdown", + ), + ], + required=False, + ), + ), + ( + "visible", + wagtail.blocks.BooleanBlock( + default=True, + required=False, + ), + ), + ( + "locked", + wagtail.blocks.BooleanBlock( + required=False + ), + ), + ( + "default_value", + wagtail.blocks.CharBlock( + help_text="Type the default value exactly as it's shown on the website page", + required=False, + ), + ), + ( + "target_value", + wagtail.blocks.CharBlock( + help_text="Type a target value if this value needs to be added to the current and all underlying sections. Type the value exactly as it's shown on the website page. Seperate multiple values by a comma (no whitespaces)", + required=False, + ), + ), + ] + ), + ), + ( + "static_image", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=False + ), + ), + ( + "holarchy_feedback_image", + wagtail.blocks.StructBlock( + [ + ( + "image_selector", + main.blocks.holon_image_chooser.HolonImageChooserBlock(), + ), + ( + "conditions", + wagtail.blocks.StreamBlock( + [ + ( + "interactive_input_condition", + wagtail.blocks.StructBlock( + [ + ( + "parameter", + wagtailmodelchooser.blocks.ModelChooserBlock( + help_text="Choose an Interactive Element of type `Single select` or `Continuous`", + target_model="holon.interactiveelement", + ), + ), + ( + "operator", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bigger", + "Bigger", + ), + ( + "biggerequal", + "Bigger or Equal", + ), + ( + "equal", + "Equal", + ), + ( + "notequal", + "Not Equal", + ), + ( + "lower", + "Lower", + ), + ( + "lowerequal", + "Lower or Equal", + ), + ], + help_text="Set the operator of this condition", + max_length=50, + ), + ), + ( + "value", + wagtail.blocks.CharBlock( + help_text="Set the value of this condition to compare to, this is the value of the slider or the value of the radio/checkbox (field 'Option' within Interactive Element )", + max_length=255, + required=True, + ), + ), + ] + ), + ) + ], + block_counts={}, + help_text="Image will only be shown when ALL conditions of a holarchy feedback image are true", + use_json_field=True, + ), + ), + ] + ), + ), + ( + "legend_items", + wagtail.blocks.StructBlock( + [ + ( + "legend_items", + wagtail.blocks.StreamBlock( + [ + ( + "item", + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "image_selector", + main.blocks.legend_item.LegendaImageChooserBlock( + required=True + ), + ), + ( + "type", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "line", + "Line", + ), + ( + "color", + "Color", + ), + ], + required=False, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add Legend items", + use_json_field=True, + ), + ) + ] + ), + ), + ], + block_counts={"static_image": {"max_num": 1}}, + ), + ), + ] + ), + ), + ( + "heroblock", + wagtail.blocks.StructBlock( + [ + ( + "background_color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("", "Default color"), + ("block__bg-gray", "Pale gray"), + ("block__bg-purple", "Pale purple"), + ], + required=False, + ), + ), + ( + "title", + wagtail.blocks.CharBlock( + form_classname="title", required=True + ), + ), + ( + "text", + main.blocks.rich_text_block.RichtextBlock( + required=True + ), + ), + ( + "media", + wagtail.blocks.StreamBlock( + [ + ( + "image", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=False + ), + ), + ( + "video", + wagtail.embeds.blocks.EmbedBlock( + required=False + ), + ), + ], + help_text="Choose an image or paste an embed url", + max_num=1, + ), + ), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Fill in this alt-text only when you want to describe the image (for screenreaders and SEO)", + required=False, + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ( + "title_block", + wagtail.blocks.StructBlock( + [ + ( + "background_color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("", "Default color"), + ("block__bg-gray", "Pale gray"), + ("block__bg-purple", "Pale purple"), + ], + required=False, + ), + ), + ("title", wagtail.blocks.CharBlock(required=True)), + ( + "size", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ("", "Select header size"), + ("h1", "H1"), + ("h2", "H2"), + ], + ), + ), + ( + "text", + main.blocks.rich_text_block.RichtextBlock( + required=False + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ( + "card_block", + wagtail.blocks.StructBlock( + [ + ( + "cards", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.CharBlock( + required=False + ), + ), + ( + "image_selector", + main.blocks.holon_image_chooser.HolonImageChooserBlock(), + ), + ( + "description", + wagtail.blocks.CharBlock( + max_length=255, required=False + ), + ), + ( + "card_color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("card__bg-gold", "Gold"), + ("card__bg-blue", "Blue"), + ("card__bg-gray", "Gray"), + ( + "card__bg-purple", + "Purple", + ), + ("card__bg-pink", "Pink"), + ( + "card__bg-orange", + "Orange", + ), + ], + required=False, + ), + ), + ( + "item_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the card to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the card should link externally", + required=False, + ), + ), + ], + help_text="Optional: add an internal or external link to the card", + max_num=1, + required=False, + ), + ), + ] + ) + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ], + use_json_field=True, + ), + ), + migrations.AlterField( + model_name="storylinepage", + name="storyline", + field=wagtail.fields.StreamField( + [ + ( + "header_full_image_block", + wagtail.blocks.StructBlock( + [ + ("title", wagtail.blocks.CharBlock(required=True)), + ( + "size", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ("", "Select header size"), + ("h1", "H1"), + ("h2", "H2"), + ], + ), + ), + ( + "image_selector", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=True + ), + ), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Fill in this alt-text only when you want to describe the image (for screenreaders and SEO)", + required=False, + ), + ), + ] + ), + ), + ( + "text_and_media", + wagtail.blocks.StructBlock( + [ + ( + "grid_layout", + wagtail.blocks.StructBlock( + [ + ( + "grid", + wagtail.blocks.ChoiceBlock( + choices=[ + ("33_66", "33% - 66%"), + ("50_50", "50% - 50%"), + ("66_33", "66% - 33%"), + ] + ), + ) + ], + required=True, + ), + ), + ( + "column_order", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ("", "Default (Text left, Media right)"), + ( + "invert", + "Invert columns (Media left, Text right)", + ), + ], + required=False, + ), + ), + ( + "background", + wagtail.blocks.StructBlock( + [ + ( + "color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("block__bg-white", "White"), + ("block__bg-gray", "Pale gray"), + ( + "block__bg-purple", + "Pale purple", + ), + ] + ), + ), + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bg__full", + "Full backgroundcolor", + ), + ( + "bg__left", + "Only backgroundcolor in the left block", + ), + ] + ), + ), + ] + ), + ), + ( + "text", + main.blocks.rich_text_block.RichtextBlock( + help_text="Add your text", + required=True, + rows=15, + ), + ), + ( + "media", + wagtail.blocks.StreamBlock( + [ + ( + "image", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=False + ), + ), + ( + "video", + wagtail.embeds.blocks.EmbedBlock( + help_text="Youtube url of vimeo url", + required=False, + ), + ), + ], + help_text="Choose an image or paste an embed url", + max_num=1, + ), + ), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Fill in this alt-text only when you want to describe the image (for screenreaders and SEO)", + required=False, + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ( + "section", + wagtail.blocks.StructBlock( + [ + ( + "background", + wagtail.blocks.StructBlock( + [ + ( + "color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("block__bg-white", "White"), + ("block__bg-gray", "Pale gray"), + ( + "block__bg-purple", + "Pale purple", + ), + ] + ), + ), + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bg__full", + "Full backgroundcolor", + ), + ( + "bg__left", + "Only backgroundcolor in the left block", + ), + ] + ), + ), + ] + ), + ), + ( + "grid_layout", + wagtail.blocks.StructBlock( + [ + ( + "grid", + wagtail.blocks.ChoiceBlock( + choices=[ + ("33_66", "33% - 66%"), + ("50_50", "50% - 50%"), + ("66_33", "66% - 33%"), + ] + ), + ) + ], + required=True, + ), + ), + ( + "text_label_national", + wagtail.blocks.CharBlock( + default="Nationaal", required=True + ), + ), + ( + "text_label_intermediate", + wagtail.blocks.CharBlock( + default="Regionaal", required=True + ), + ), + ( + "text_label_local", + wagtail.blocks.CharBlock( + default="Lokaal", required=True + ), + ), + ( + "content", + wagtail.blocks.StreamBlock( + [ + ( + "text", + main.blocks.rich_text_block.RichtextBlock(), + ), + ( + "interactive_input", + wagtail.blocks.StructBlock( + [ + ( + "interactive_input", + wagtailmodelchooser.blocks.ModelChooserBlock( + help_text="Choose an Interactive Element of type `Single select` or `Continuous`", + target_model="holon.interactiveelement", + ), + ), + ( + "display", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "checkbox_radio", + "Show as checkboxe(s) or radiobutton(s)", + ), + ( + "dropdown", + "Show as dropdown", + ), + ], + required=False, + ), + ), + ( + "visible", + wagtail.blocks.BooleanBlock( + default=True, + required=False, + ), + ), + ( + "locked", + wagtail.blocks.BooleanBlock( + required=False + ), + ), + ( + "default_value", + wagtail.blocks.CharBlock( + help_text="Type the default value exactly as it's shown on the website page", + required=False, + ), + ), + ( + "target_value", + wagtail.blocks.CharBlock( + help_text="Type a target value if this value needs to be added to the current and all underlying sections. Type the value exactly as it's shown on the website page. Seperate multiple values by a comma (no whitespaces)", + required=False, + ), + ), + ] + ), + ), + ( + "static_image", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=False + ), + ), + ( + "holarchy_feedback_image", + wagtail.blocks.StructBlock( + [ + ( + "image_selector", + main.blocks.holon_image_chooser.HolonImageChooserBlock(), + ), + ( + "conditions", + wagtail.blocks.StreamBlock( + [ + ( + "interactive_input_condition", + wagtail.blocks.StructBlock( + [ + ( + "parameter", + wagtailmodelchooser.blocks.ModelChooserBlock( + help_text="Choose an Interactive Element of type `Single select` or `Continuous`", + target_model="holon.interactiveelement", + ), + ), + ( + "operator", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "bigger", + "Bigger", + ), + ( + "biggerequal", + "Bigger or Equal", + ), + ( + "equal", + "Equal", + ), + ( + "notequal", + "Not Equal", + ), + ( + "lower", + "Lower", + ), + ( + "lowerequal", + "Lower or Equal", + ), + ], + help_text="Set the operator of this condition", + max_length=50, + ), + ), + ( + "value", + wagtail.blocks.CharBlock( + help_text="Set the value of this condition to compare to, this is the value of the slider or the value of the radio/checkbox (field 'Option' within Interactive Element )", + max_length=255, + required=True, + ), + ), + ] + ), + ) + ], + block_counts={}, + help_text="Image will only be shown when ALL conditions of a holarchy feedback image are true", + use_json_field=True, + ), + ), + ] + ), + ), + ( + "legend_items", + wagtail.blocks.StructBlock( + [ + ( + "legend_items", + wagtail.blocks.StreamBlock( + [ + ( + "item", + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "image_selector", + main.blocks.legend_item.LegendaImageChooserBlock( + required=True + ), + ), + ( + "type", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "line", + "Line", + ), + ( + "color", + "Color", + ), + ], + required=False, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add Legend items", + use_json_field=True, + ), + ) + ] + ), + ), + ], + block_counts={"static_image": {"max_num": 1}}, + ), + ), + ] + ), + ), + ( + "heroblock", + wagtail.blocks.StructBlock( + [ + ( + "background_color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("", "Default color"), + ("block__bg-gray", "Pale gray"), + ("block__bg-purple", "Pale purple"), + ], + required=False, + ), + ), + ( + "title", + wagtail.blocks.CharBlock( + form_classname="title", required=True + ), + ), + ( + "text", + main.blocks.rich_text_block.RichtextBlock( + required=True + ), + ), + ( + "media", + wagtail.blocks.StreamBlock( + [ + ( + "image", + main.blocks.holon_image_chooser.HolonImageChooserBlock( + required=False + ), + ), + ( + "video", + wagtail.embeds.blocks.EmbedBlock( + required=False + ), + ), + ], + help_text="Choose an image or paste an embed url", + max_num=1, + ), + ), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Fill in this alt-text only when you want to describe the image (for screenreaders and SEO)", + required=False, + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ( + "title_block", + wagtail.blocks.StructBlock( + [ + ( + "background_color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("", "Default color"), + ("block__bg-gray", "Pale gray"), + ("block__bg-purple", "Pale purple"), + ], + required=False, + ), + ), + ("title", wagtail.blocks.CharBlock(required=True)), + ( + "size", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ("", "Select header size"), + ("h1", "H1"), + ("h2", "H2"), + ], + ), + ), + ( + "text", + main.blocks.rich_text_block.RichtextBlock( + required=False + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ( + "card_block", + wagtail.blocks.StructBlock( + [ + ( + "cards", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.CharBlock( + required=False + ), + ), + ( + "image_selector", + main.blocks.holon_image_chooser.HolonImageChooserBlock(), + ), + ( + "description", + wagtail.blocks.CharBlock( + max_length=255, required=False + ), + ), + ( + "card_color", + wagtail.blocks.ChoiceBlock( + choices=[ + ("card__bg-gold", "Gold"), + ("card__bg-blue", "Blue"), + ("card__bg-gray", "Gray"), + ( + "card__bg-purple", + "Purple", + ), + ("card__bg-pink", "Pink"), + ( + "card__bg-orange", + "Orange", + ), + ], + required=False, + ), + ), + ( + "item_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the card to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the card should link externally", + required=False, + ), + ), + ], + help_text="Optional: add an internal or external link to the card", + max_num=1, + required=False, + ), + ), + ] + ) + ), + ), + ( + "button_block", + wagtail.blocks.StreamBlock( + [ + ( + "buttons", + wagtail.blocks.StructBlock( + [ + ( + "buttons_align", + wagtail.blocks.ChoiceBlock( + choices=[ + ( + "btn-left", + "left", + ), + ( + "btn-center", + "center", + ), + ( + "btn-right", + "right", + ), + ], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ( + "button_style", + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[ + ( + "dark", + "Default (Dark blue)", + ), + ( + "arrow", + "Dark blue with arrow", + ), + ( + "light", + "light", + ), + ], + required=False, + ), + ), + ( + "button_text", + wagtail.blocks.CharBlock( + required=True + ), + ), + ( + "button_link", + wagtail.blocks.StreamBlock( + [ + ( + "intern", + main.blocks.page_chooser_block.PageChooserBlock( + helptext="Choose if you want the button to link to a page internally", + required=False, + ), + ), + ( + "extern", + wagtail.blocks.URLBlock( + helptext="Fill in if the button should link externally", + required=False, + ), + ), + ], + help_text="Where do you want the button to link to", + max_num=1, + ), + ), + ], + required=True, + ), + ) + ], + help_text="Add a button", + min_num=1, + ), + ), + ], + required=False, + ), + ) + ], + required=False, + ), + ), + ] + ), + ), + ], + use_json_field=True, + ), + ), + ] From 3e5830362be9355501070c747e23fafa258df027 Mon Sep 17 00:00:00 2001 From: Erik van Velzen Date: Thu, 20 Apr 2023 12:53:19 +0200 Subject: [PATCH 18/29] Enable sentry monitoring Sentry is a monitoring platform which does tracing to give insight into the application. It is accessible through https://zenmo.sentry.io/projects/holon/ . DM me for an account. You can distinguish your local enviroment in Sentry by defining the environment variable SENTRY_ENVIRONMENT for Python. For example set SENTRY_ENVIRONMENT=erik. You can start submitting traces by defining the environment variable SENTRY_DSN. For example set SENTRY_DSN=https://764e9f2b886741bcbcfd2acd74a7f7b0@o4505045746384896.ingest.sentry.io/4505045759361024 I am not familiar with Django configuration so any feedback on that part is most welcome. --- .devcontainer/.env.example | 4 ++++ docker/config/python.example.env | 3 ++- docker/config/python.pizza.env | 3 ++- src/pipit/settings/__init__.py | 36 ++++++++++++++++++++++++++++++++ src/pipit/settings/local.py | 6 ++++++ src/pipit/settings/prod.py | 10 +++++---- src/pipit/settings/stage.py | 16 ++++---------- src/requirements/base.txt | 2 +- 8 files changed, 61 insertions(+), 19 deletions(-) diff --git a/.devcontainer/.env.example b/.devcontainer/.env.example index 1322fc869..7082445f8 100644 --- a/.devcontainer/.env.example +++ b/.devcontainer/.env.example @@ -19,6 +19,10 @@ DB_PASSWORD=postgres DB_HOST=db DB_PORT=5432 +## uncomment DSN to opt-in to Sentry +# SENTRY_DSN=https://764e9f2b886741bcbcfd2acd74a7f7b0@o4505045746384896.ingest.sentry.io/4505045759361024 +SENTRY_ENVIRONMENT=devcontainer + #FRONTEND NEXT_PUBLIC_WAGTAIL_API_URL=http://localhost:8000/wt/api/nextjs diff --git a/docker/config/python.example.env b/docker/config/python.example.env index 94073ce28..0b9ed6678 100644 --- a/docker/config/python.example.env +++ b/docker/config/python.example.env @@ -6,4 +6,5 @@ DEBUG_TOOLBAR=True DB_NAME=postgres DB_USER=postgres DB_PASSWORD=postgres -DB_HOST=db \ No newline at end of file +DB_HOST=db +SENTRY_ENVIRONMENT= diff --git a/docker/config/python.pizza.env b/docker/config/python.pizza.env index ff08e0b8b..593bc8e42 100644 --- a/docker/config/python.pizza.env +++ b/docker/config/python.pizza.env @@ -13,4 +13,5 @@ AZURE_ACCOUNT_NAME=holonstorage CUSTOM_STATIC_LOCATION="static-acceptatie" CUSTOM_MEDIA_LOCATION="media-acceptatie" SECRET_KEY= -AZURE_STORAGE_KEY= \ No newline at end of file +AZURE_STORAGE_KEY= +SENTRY_ENVIRONMENT=pizzaoven diff --git a/src/pipit/settings/__init__.py b/src/pipit/settings/__init__.py index f7c66b8ee..d0aef8cb7 100644 --- a/src/pipit/settings/__init__.py +++ b/src/pipit/settings/__init__.py @@ -1,8 +1,11 @@ from __future__ import absolute_import, unicode_literals import os +from typing import Optional, Dict, Any from django.core.exceptions import ImproperlyConfigured +import sentry_sdk +from sentry_sdk.integrations.django import DjangoIntegration def get_env(name, default=None): @@ -19,3 +22,36 @@ def get_env(name, default=None): def get_env_bool(name, default=None): return get_env(name, default=default) == "True" + + +def initialize_sentry(ingest_dsn: str, environment: str) -> None: + if ingest_dsn == "": + return + + sentry_sdk.init( + dsn=ingest_dsn, + environment=environment, + debug=False, + traces_sample_rate=1.0, + integrations=[ + DjangoIntegration( + # Nothing interesting here + middleware_spans=False, + # Wagtail produces a lot of signals + signals_spans=False, + ) + ], + release="0.1.0", + # We do too many queries on some pages. + # Is there a better way to reduce the number of spans? + _experiments={"max_spans": 5000}, # default 1000 + before_send_transaction=remove_db_spans, + ) + + +# Some actions produce many database queries. This exceeds the span limit of Sentry (1000). +# This function removes those spans so there is enough room left to send more relevant data. +def remove_db_spans(event: Dict[str, Any], hint: Dict[str, Any]) -> Optional[Dict[str, Any]]: + event["spans"] = [span for span in event["spans"] if span["op"] != "db"] + + return event diff --git a/src/pipit/settings/local.py b/src/pipit/settings/local.py index df5a0bc83..7b712bc69 100644 --- a/src/pipit/settings/local.py +++ b/src/pipit/settings/local.py @@ -1,6 +1,7 @@ """ Write local settings here, or override base settings """ +from pipit.settings import initialize_sentry from pipit.settings.base import * # NOQA WAGTAILADMIN_BASE_URL = "http://localhost:8000" @@ -22,6 +23,11 @@ INTERNAL_IPS = get_env("INTERNAL_IPS", default="").split(",") +# Sentry +SENTRY_DSN = get_env("SENTRY_DSN", "") +SENTRY_ENVIRONMENT = get_env("SENTRY_ENVIRONMENT", "local") +initialize_sentry(SENTRY_DSN, SENTRY_ENVIRONMENT) + # Add django debug toolbar when using local version if get_env_bool("DEBUG_TOOLBAR", default=True): DEBUG_TOOLBAR_PATCH_SETTINGS = False diff --git a/src/pipit/settings/prod.py b/src/pipit/settings/prod.py index 182d435e6..482ce5c9e 100644 --- a/src/pipit/settings/prod.py +++ b/src/pipit/settings/prod.py @@ -1,10 +1,7 @@ """ Write prod settings here, or override base settings """ -import sentry_sdk -from sentry_sdk import configure_scope -from sentry_sdk.integrations.django import DjangoIntegration - +from pipit.settings import initialize_sentry from pipit.settings.base import * # NOQA @@ -74,6 +71,11 @@ # Use a secure cookie for the CSRF cookie CSRF_COOKIE_SECURE = True +# Sentry +SENTRY_DSN = get_env("SENTRY_DSN", "") +SENTRY_ENVIRONMENT = get_env("SENTRY_ENVIRONMENT", "production") +initialize_sentry(SENTRY_DSN, SENTRY_ENVIRONMENT) + # Log to console to get logging output from docker LOGGING = { "version": 1, diff --git a/src/pipit/settings/stage.py b/src/pipit/settings/stage.py index 975de333b..dbbc1bf08 100644 --- a/src/pipit/settings/stage.py +++ b/src/pipit/settings/stage.py @@ -1,10 +1,9 @@ """ Write stage settings here, or override base settings """ -import sentry_sdk from sentry_sdk import configure_scope -from sentry_sdk.integrations.django import DjangoIntegration +from pipit.settings import initialize_sentry from pipit.settings.base import * # NOQA @@ -59,16 +58,9 @@ CSRF_COOKIE_SECURE = True # Sentry -SENTRY_DSN = get_env("SENTRY_DSN") -SENTRY_ENVIRONMENT = "stage" - -sentry_sdk.init( - dsn=SENTRY_DSN, - release=APP_VERSION, - environment=SENTRY_ENVIRONMENT, - debug=True, - integrations=[DjangoIntegration()], -) +SENTRY_DSN = get_env("SENTRY_DSN", "") +SENTRY_ENVIRONMENT = get_env("SENTRY_ENVIRONMENT", "stage") +initialize_sentry(SENTRY_DSN, SENTRY_ENVIRONMENT) # Add sentry to logging with configure_scope() as scope: diff --git a/src/requirements/base.txt b/src/requirements/base.txt index d6a04302b..90b3f3dac 100644 --- a/src/requirements/base.txt +++ b/src/requirements/base.txt @@ -2,7 +2,7 @@ Django>=4.1,<4.2 boto3>1.19,<1.25 django-storages==1.13 psycopg2==2.9.3 -sentry_sdk==1.9 +sentry_sdk==1.20.0 python-dotenv==0.21 wagtail>=4.1,<4.2 wagtail-meta-preview From b02e4e3dc2cce016c9b4508ecb2808f9f2c36131 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Tue, 25 Apr 2023 09:07:05 +0200 Subject: [PATCH 19/29] adds tvw small version and set of relations increased --- src/holon/fixtures/jorrit/ref/tvw-CLEANSMALL.json | 1 + src/holon/fixtures/utils/reset_pk_fk_ptr.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 src/holon/fixtures/jorrit/ref/tvw-CLEANSMALL.json diff --git a/src/holon/fixtures/jorrit/ref/tvw-CLEANSMALL.json b/src/holon/fixtures/jorrit/ref/tvw-CLEANSMALL.json new file mode 100644 index 000000000..1f26e6a36 --- /dev/null +++ b/src/holon/fixtures/jorrit/ref/tvw-CLEANSMALL.json @@ -0,0 +1 @@ +[{"model": "holon.scenario", "pk": 444001, "fields": {"name": "Basis - Gasburner for all", "version": 1, "comment": "Basis-scenario - huidige toestand met cv-ketels voor iedereen. Dieselauto's en geen Zon-pv. Restwarmtebronnen wel aanwezige.", "cloned_from": null}}, {"model": "holon.actorgroup", "pk": 444001, "fields": {"name": "COMMERCIAL"}}, {"model": "holon.actorgroup", "pk": 444002, "fields": {"name": "HOUSEHOLD"}}, {"model": "holon.actor", "pk": 444001, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "OPERATORGRID", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444002, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "HOLONENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444003, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "HOLONENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444004, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "HOLONENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444005, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "HOLONENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444006, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "HOLONENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444007, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "HOLONENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444008, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "HOLONENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444010, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444002, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444011, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444001, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444012, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444002, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444013, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444002, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444014, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444002, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444015, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444002, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444016, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444002, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444018, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444001, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444019, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444001, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444020, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444001, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444021, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444001, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444022, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "CONNECTIONOWNER", "payload": 444001, "group": 444002, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444023, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "SUPPLIERENERGY", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.actor", "pk": 444024, "fields": {"polymorphic_ctype": ["holon", "actor"], "category": "GOVHOLON", "payload": 444001, "group": null, "subgroup": null, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444013, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": null, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444014, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444015, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444016, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444017, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444018, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444019, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444020, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444021, "fields": {"polymorphic_ctype": ["holon", "electricgridnode"], "owner_actor": 444001, "capacity_kw": 5000.0, "parent": 444013, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444023, "fields": {"polymorphic_ctype": ["holon", "heatgridnode"], "owner_actor": 444001, "capacity_kw": 500000.0, "parent": null, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.gridnode", "pk": 444024, "fields": {"polymorphic_ctype": ["holon", "heatgridnode"], "owner_actor": 444001, "capacity_kw": 500000.0, "parent": null, "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.electricgridnode", "pk": 444013, "fields": {"gridnode_ptr": 444013, "type": "HSMS"}}, {"model": "holon.electricgridnode", "pk": 444014, "fields": {"gridnode_ptr": 444014, "type": "MSLS"}}, {"model": "holon.electricgridnode", "pk": 444015, "fields": {"gridnode_ptr": 444015, "type": "MSLS"}}, {"model": "holon.electricgridnode", "pk": 444016, "fields": {"gridnode_ptr": 444016, "type": "MSLS"}}, {"model": "holon.electricgridnode", "pk": 444017, "fields": {"gridnode_ptr": 444017, "type": "MSLS"}}, {"model": "holon.electricgridnode", "pk": 444018, "fields": {"gridnode_ptr": 444018, "type": "MSLS"}}, {"model": "holon.electricgridnode", "pk": 444019, "fields": {"gridnode_ptr": 444019, "type": "MSLS"}}, {"model": "holon.electricgridnode", "pk": 444020, "fields": {"gridnode_ptr": 444020, "type": "MSLS"}}, {"model": "holon.electricgridnode", "pk": 444021, "fields": {"gridnode_ptr": 444021, "type": "MSLS"}}, {"model": "holon.heatgridnode", "pk": 444023, "fields": {"gridnode_ptr": 444023, "type": "HT"}}, {"model": "holon.heatgridnode", "pk": 444024, "fields": {"gridnode_ptr": 444024, "type": "MT"}}, {"model": "holon.gridconnection", "pk": 444001, "fields": {"polymorphic_ctype": ["holon", "housegridconnection"], "owner_actor": 444010, "capacity_kw": 17.0, "parent_electric": 444014, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444002, "fields": {"polymorphic_ctype": ["holon", "buildinggridconnection"], "owner_actor": 444011, "capacity_kw": 30.0, "parent_electric": 444014, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444003, "fields": {"polymorphic_ctype": ["holon", "housegridconnection"], "owner_actor": 444012, "capacity_kw": 17.0, "parent_electric": 444015, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444004, "fields": {"polymorphic_ctype": ["holon", "housegridconnection"], "owner_actor": 444013, "capacity_kw": 17.0, "parent_electric": 444016, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444005, "fields": {"polymorphic_ctype": ["holon", "housegridconnection"], "owner_actor": 444014, "capacity_kw": 17.0, "parent_electric": 444017, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444006, "fields": {"polymorphic_ctype": ["holon", "housegridconnection"], "owner_actor": 444015, "capacity_kw": 17.0, "parent_electric": 444018, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444007, "fields": {"polymorphic_ctype": ["holon", "housegridconnection"], "owner_actor": 444016, "capacity_kw": 17.0, "parent_electric": 444019, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444008, "fields": {"polymorphic_ctype": ["holon", "industrygridconnection"], "owner_actor": 444018, "capacity_kw": 1000.0, "parent_electric": 444020, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444009, "fields": {"polymorphic_ctype": ["holon", "productiongridconnection"], "owner_actor": 444019, "capacity_kw": 1000.0, "parent_electric": 444020, "parent_heat": 444023, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444010, "fields": {"polymorphic_ctype": ["holon", "districtheatinggridconnection"], "owner_actor": 444020, "capacity_kw": 1000.0, "parent_electric": 444020, "parent_heat": 444023, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444011, "fields": {"polymorphic_ctype": ["holon", "districtheatinggridconnection"], "owner_actor": 444021, "capacity_kw": 1000.0, "parent_electric": 444021, "parent_heat": 444024, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.gridconnection", "pk": 444012, "fields": {"polymorphic_ctype": ["holon", "housegridconnection"], "owner_actor": 444022, "capacity_kw": 17.0, "parent_electric": 444018, "parent_heat": null, "charging_mode": "SIMPLE", "battery_mode": null, "electrolyser_mode": null, "payload": 444001, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444001, "fields": {"gridconnection_ptr": 444001, "insulation_label": 4, "heating_type": "GASBURNER", "tempSetpointNight_degC": 16.0, "tempSetpointNight_start_hr": 20.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 8.0, "pricelevelLowDifFromAvg_eurpkWh": 0.018, "pricelevelHighDifFromAvg_eurpkWh": 0.009}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444002, "fields": {"gridconnection_ptr": 444002, "insulation_label": 4, "heating_type": "GASBURNER", "tempSetpointNight_degC": 16.0, "tempSetpointNight_start_hr": 20.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 8.0, "pricelevelLowDifFromAvg_eurpkWh": null, "pricelevelHighDifFromAvg_eurpkWh": null}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444003, "fields": {"gridconnection_ptr": 444003, "insulation_label": 6, "heating_type": "GASBURNER", "tempSetpointNight_degC": 15.0, "tempSetpointNight_start_hr": 23.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 7.0, "pricelevelLowDifFromAvg_eurpkWh": 0.018, "pricelevelHighDifFromAvg_eurpkWh": 0.09}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444004, "fields": {"gridconnection_ptr": 444004, "insulation_label": 7, "heating_type": "GASBURNER", "tempSetpointNight_degC": 16.0, "tempSetpointNight_start_hr": 20.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 8.0, "pricelevelLowDifFromAvg_eurpkWh": null, "pricelevelHighDifFromAvg_eurpkWh": null}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444005, "fields": {"gridconnection_ptr": 444005, "insulation_label": 5, "heating_type": "GASBURNER", "tempSetpointNight_degC": 16.0, "tempSetpointNight_start_hr": 20.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 8.0, "pricelevelLowDifFromAvg_eurpkWh": 0.018, "pricelevelHighDifFromAvg_eurpkWh": 0.009}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444006, "fields": {"gridconnection_ptr": 444006, "insulation_label": 5, "heating_type": "GASBURNER", "tempSetpointNight_degC": 16.0, "tempSetpointNight_start_hr": 20.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 8.0, "pricelevelLowDifFromAvg_eurpkWh": 0.018, "pricelevelHighDifFromAvg_eurpkWh": 0.09}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444007, "fields": {"gridconnection_ptr": 444007, "insulation_label": 2, "heating_type": "GASBURNER", "tempSetpointNight_degC": 16.0, "tempSetpointNight_start_hr": 20.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 8.0, "pricelevelLowDifFromAvg_eurpkWh": 0.018, "pricelevelHighDifFromAvg_eurpkWh": 0.09}}, {"model": "holon.builtenvironmentgridconnection", "pk": 444012, "fields": {"gridconnection_ptr": 444012, "insulation_label": 5, "heating_type": "GASBURNER", "tempSetpointNight_degC": 16.0, "tempSetpointNight_start_hr": 20.0, "tempSetpointDay_degC": 20.0, "tempSetpointDay_start_hr": 8.0, "pricelevelLowDifFromAvg_eurpkWh": 0.018, "pricelevelHighDifFromAvg_eurpkWh": 0.09}}, {"model": "holon.utilitygridconnection", "pk": 444008, "fields": {"gridconnection_ptr": 444008, "heating_type": "GASBURNER"}}, {"model": "holon.utilitygridconnection", "pk": 444010, "fields": {"gridconnection_ptr": 444010, "heating_type": "GASFIRED_CHPPEAK"}}, {"model": "holon.utilitygridconnection", "pk": 444011, "fields": {"gridconnection_ptr": 444011, "heating_type": "LT_RESIDUAL_HEATPUMP_GASPEAK"}}, {"model": "holon.housegridconnection", "pk": 444001, "fields": {"builtenvironmentgridconnection_ptr": 444001, "type": "APPARTMENT", "smart_assets": false}}, {"model": "holon.housegridconnection", "pk": 444003, "fields": {"builtenvironmentgridconnection_ptr": 444003, "type": "SEMIDETACHED", "smart_assets": false}}, {"model": "holon.housegridconnection", "pk": 444004, "fields": {"builtenvironmentgridconnection_ptr": 444004, "type": "APPARTMENT", "smart_assets": false}}, {"model": "holon.housegridconnection", "pk": 444005, "fields": {"builtenvironmentgridconnection_ptr": 444005, "type": "HIGHRISE", "smart_assets": false}}, {"model": "holon.housegridconnection", "pk": 444006, "fields": {"builtenvironmentgridconnection_ptr": 444006, "type": "TERRACED", "smart_assets": false}}, {"model": "holon.housegridconnection", "pk": 444007, "fields": {"builtenvironmentgridconnection_ptr": 444007, "type": "DETACHED", "smart_assets": false}}, {"model": "holon.housegridconnection", "pk": 444012, "fields": {"builtenvironmentgridconnection_ptr": 444012, "type": "SEMIDETACHED", "smart_assets": false}}, {"model": "holon.buildinggridconnection", "pk": 444002, "fields": {"builtenvironmentgridconnection_ptr": 444002, "type": "STORE"}}, {"model": "holon.productiongridconnection", "pk": 444009, "fields": {"gridconnection_ptr": 444009, "category": "RESIDUALHEAT"}}, {"model": "holon.industrygridconnection", "pk": 444008, "fields": {"utilitygridconnection_ptr": 444008, "type": "INDUSTRY_OTHER"}}, {"model": "holon.districtheatinggridconnection", "pk": 444010, "fields": {"utilitygridconnection_ptr": 444010, "type": "HT", "smart_assets": false}}, {"model": "holon.districtheatinggridconnection", "pk": 444011, "fields": {"utilitygridconnection_ptr": 444011, "type": "MT", "smart_assets": false}}, {"model": "holon.energyasset", "pk": 444001, "fields": {"polymorphic_ctype": ["holon", "productionasset"], "gridconnection": 444009, "gridnode": null, "name": "Residual_heat", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444002, "fields": {"polymorphic_ctype": ["holon", "productionasset"], "gridconnection": 444011, "gridnode": null, "name": "Residual_heat", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444006, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444011, "gridnode": null, "name": "District_Heating_heat_buffer_MT_S", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444009, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444010, "gridnode": null, "name": "District_Heating_heat_buffer_HT_S", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444010, "fields": {"polymorphic_ctype": ["holon", "heatproductionasset"], "gridconnection": 444009, "gridnode": null, "name": "Residual_heat", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444012, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444009, "gridnode": null, "name": "CurtailerHeat", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444013, "fields": {"polymorphic_ctype": ["holon", "heatproductionasset"], "gridconnection": 444011, "gridnode": null, "name": "Residual_heat", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444014, "fields": {"polymorphic_ctype": ["holon", "electricheatconversionasset"], "gridconnection": 444011, "gridnode": null, "name": "DH_heat_pump_water_MT_M", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444015, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444011, "gridnode": null, "name": "DH_boiler_L", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444017, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": null, "gridnode": 444023, "name": "District_Heating_network_HT_M", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444018, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": null, "gridnode": 444024, "name": "District_Heating_network_MT_S", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444019, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444001, "gridnode": null, "name": "House_heatmodel_D", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444020, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444001, "gridnode": null, "name": "House_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444021, "fields": {"polymorphic_ctype": ["holon", "heatconsumptionasset"], "gridconnection": 444001, "gridnode": null, "name": "House_hot_water", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444022, "fields": {"polymorphic_ctype": ["holon", "cookingconversionasset"], "gridconnection": 444001, "gridnode": null, "name": "Gas pit", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444023, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444001, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444024, "fields": {"polymorphic_ctype": ["holon", "dieselvehicleasset"], "gridconnection": 444001, "gridnode": null, "name": "Diesel_Vehicle", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444025, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444002, "gridnode": null, "name": "House_heatmodel_D", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444026, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444002, "gridnode": null, "name": "Store_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444027, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444002, "gridnode": null, "name": "Building_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444028, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444003, "gridnode": null, "name": "House_heatmodel_B", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444029, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444003, "gridnode": null, "name": "House_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444030, "fields": {"polymorphic_ctype": ["holon", "heatconsumptionasset"], "gridconnection": 444003, "gridnode": null, "name": "House_hot_wate", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444031, "fields": {"polymorphic_ctype": ["holon", "cookingconversionasset"], "gridconnection": 444003, "gridnode": null, "name": "Gas pit", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444032, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444003, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444033, "fields": {"polymorphic_ctype": ["holon", "dieselvehicleasset"], "gridconnection": 444003, "gridnode": null, "name": "Diesel_Vehicle", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444034, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444004, "gridnode": null, "name": "House_heatmodel_A", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444035, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444004, "gridnode": null, "name": "House_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444036, "fields": {"polymorphic_ctype": ["holon", "heatconsumptionasset"], "gridconnection": 444004, "gridnode": null, "name": "House_hot_water", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444037, "fields": {"polymorphic_ctype": ["holon", "cookingconversionasset"], "gridconnection": 444004, "gridnode": null, "name": "Gas pit", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444038, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444004, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444039, "fields": {"polymorphic_ctype": ["holon", "dieselvehicleasset"], "gridconnection": 444004, "gridnode": null, "name": "Diesel_Vehicle", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444040, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444005, "gridnode": null, "name": "House_heatmodel_C", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444041, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444005, "gridnode": null, "name": "House_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444042, "fields": {"polymorphic_ctype": ["holon", "heatconsumptionasset"], "gridconnection": 444005, "gridnode": null, "name": "House_hot_water", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444043, "fields": {"polymorphic_ctype": ["holon", "cookingconversionasset"], "gridconnection": 444005, "gridnode": null, "name": "Gas pit", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444044, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444005, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444045, "fields": {"polymorphic_ctype": ["holon", "dieselvehicleasset"], "gridconnection": 444005, "gridnode": null, "name": "Diesel_Vehicle", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444046, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444006, "gridnode": null, "name": "House_heatmodel_C", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444047, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444006, "gridnode": null, "name": "House_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444048, "fields": {"polymorphic_ctype": ["holon", "heatconsumptionasset"], "gridconnection": 444006, "gridnode": null, "name": "House_hot_water", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444049, "fields": {"polymorphic_ctype": ["holon", "cookingconversionasset"], "gridconnection": 444006, "gridnode": null, "name": "Gas pit", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444050, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444006, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444051, "fields": {"polymorphic_ctype": ["holon", "dieselvehicleasset"], "gridconnection": 444006, "gridnode": null, "name": "Diesel_Vehicle", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444052, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444012, "gridnode": null, "name": "House_heatmodel_C", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444053, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444012, "gridnode": null, "name": "House_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444054, "fields": {"polymorphic_ctype": ["holon", "heatconsumptionasset"], "gridconnection": 444012, "gridnode": null, "name": "House_hot_water", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444055, "fields": {"polymorphic_ctype": ["holon", "cookingconversionasset"], "gridconnection": 444012, "gridnode": null, "name": "Gas pit", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444056, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444012, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444057, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444012, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444058, "fields": {"polymorphic_ctype": ["holon", "dieselvehicleasset"], "gridconnection": 444012, "gridnode": null, "name": "Diesel_Vehicle", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444059, "fields": {"polymorphic_ctype": ["holon", "heatstorageasset"], "gridconnection": 444007, "gridnode": null, "name": "House_heatmodel_F", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444060, "fields": {"polymorphic_ctype": ["holon", "electricconsumptionasset"], "gridconnection": 444007, "gridnode": null, "name": "House_other_electricity", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444061, "fields": {"polymorphic_ctype": ["holon", "heatconsumptionasset"], "gridconnection": 444007, "gridnode": null, "name": "House_hot_water", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444062, "fields": {"polymorphic_ctype": ["holon", "cookingconversionasset"], "gridconnection": 444007, "gridnode": null, "name": "Gas pit", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444063, "fields": {"polymorphic_ctype": ["holon", "chemicalheatconversionasset"], "gridconnection": 444007, "gridnode": null, "name": "House_gas_burner", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444064, "fields": {"polymorphic_ctype": ["holon", "dieselvehicleasset"], "gridconnection": 444007, "gridnode": null, "name": "Diesel_Vehicle", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444065, "fields": {"polymorphic_ctype": ["holon", "hybridheatcoversionasset"], "gridconnection": 444010, "gridnode": null, "name": "Methane_CHP_M", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.energyasset", "pk": 444067, "fields": {"polymorphic_ctype": ["holon", "transportheatconversionasset"], "gridconnection": 444011, "gridnode": null, "name": "DH_heat_pump_water_MT_M", "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.consumptionasset", "pk": 444020, "fields": {"energyasset_ptr": 444020, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444021, "fields": {"energyasset_ptr": 444021, "type": "HOT_WATER_CONSUMPTION"}}, {"model": "holon.consumptionasset", "pk": 444024, "fields": {"energyasset_ptr": 444024, "type": "DIESEL_VEHICLE"}}, {"model": "holon.consumptionasset", "pk": 444026, "fields": {"energyasset_ptr": 444026, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444029, "fields": {"energyasset_ptr": 444029, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444030, "fields": {"energyasset_ptr": 444030, "type": "HOT_WATER_CONSUMPTION"}}, {"model": "holon.consumptionasset", "pk": 444033, "fields": {"energyasset_ptr": 444033, "type": "DIESEL_VEHICLE"}}, {"model": "holon.consumptionasset", "pk": 444035, "fields": {"energyasset_ptr": 444035, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444036, "fields": {"energyasset_ptr": 444036, "type": "HOT_WATER_CONSUMPTION"}}, {"model": "holon.consumptionasset", "pk": 444039, "fields": {"energyasset_ptr": 444039, "type": "DIESEL_VEHICLE"}}, {"model": "holon.consumptionasset", "pk": 444041, "fields": {"energyasset_ptr": 444041, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444042, "fields": {"energyasset_ptr": 444042, "type": "HOT_WATER_CONSUMPTION"}}, {"model": "holon.consumptionasset", "pk": 444045, "fields": {"energyasset_ptr": 444045, "type": "DIESEL_VEHICLE"}}, {"model": "holon.consumptionasset", "pk": 444047, "fields": {"energyasset_ptr": 444047, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444048, "fields": {"energyasset_ptr": 444048, "type": "HOT_WATER_CONSUMPTION"}}, {"model": "holon.consumptionasset", "pk": 444051, "fields": {"energyasset_ptr": 444051, "type": "DIESEL_VEHICLE"}}, {"model": "holon.consumptionasset", "pk": 444053, "fields": {"energyasset_ptr": 444053, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444054, "fields": {"energyasset_ptr": 444054, "type": "HOT_WATER_CONSUMPTION"}}, {"model": "holon.consumptionasset", "pk": 444058, "fields": {"energyasset_ptr": 444058, "type": "DIESEL_VEHICLE"}}, {"model": "holon.consumptionasset", "pk": 444060, "fields": {"energyasset_ptr": 444060, "type": "ELECTRICITY_DEMAND"}}, {"model": "holon.consumptionasset", "pk": 444061, "fields": {"energyasset_ptr": 444061, "type": "HOT_WATER_CONSUMPTION"}}, {"model": "holon.consumptionasset", "pk": 444064, "fields": {"energyasset_ptr": 444064, "type": "DIESEL_VEHICLE"}}, {"model": "holon.dieselvehicleasset", "pk": 444024, "fields": {"consumptionasset_ptr": 444024, "energyConsumption_kWhpkm": 0.8, "vehicleScaling": 1}}, {"model": "holon.dieselvehicleasset", "pk": 444033, "fields": {"consumptionasset_ptr": 444033, "energyConsumption_kWhpkm": 0.8, "vehicleScaling": 1}}, {"model": "holon.dieselvehicleasset", "pk": 444039, "fields": {"consumptionasset_ptr": 444039, "energyConsumption_kWhpkm": 0.8, "vehicleScaling": 1}}, {"model": "holon.dieselvehicleasset", "pk": 444045, "fields": {"consumptionasset_ptr": 444045, "energyConsumption_kWhpkm": 0.8, "vehicleScaling": 1}}, {"model": "holon.dieselvehicleasset", "pk": 444051, "fields": {"consumptionasset_ptr": 444051, "energyConsumption_kWhpkm": 0.8, "vehicleScaling": 1}}, {"model": "holon.dieselvehicleasset", "pk": 444058, "fields": {"consumptionasset_ptr": 444058, "energyConsumption_kWhpkm": 0.8, "vehicleScaling": 1}}, {"model": "holon.dieselvehicleasset", "pk": 444064, "fields": {"consumptionasset_ptr": 444064, "energyConsumption_kWhpkm": 0.8, "vehicleScaling": 1}}, {"model": "holon.heatconsumptionasset", "pk": 444021, "fields": {"consumptionasset_ptr": 444021, "yearlyDemandHeat_kWh": 2000.0}}, {"model": "holon.heatconsumptionasset", "pk": 444030, "fields": {"consumptionasset_ptr": 444030, "yearlyDemandHeat_kWh": 2000.0}}, {"model": "holon.heatconsumptionasset", "pk": 444036, "fields": {"consumptionasset_ptr": 444036, "yearlyDemandHeat_kWh": 2000.0}}, {"model": "holon.heatconsumptionasset", "pk": 444042, "fields": {"consumptionasset_ptr": 444042, "yearlyDemandHeat_kWh": 2000.0}}, {"model": "holon.heatconsumptionasset", "pk": 444048, "fields": {"consumptionasset_ptr": 444048, "yearlyDemandHeat_kWh": 2000.0}}, {"model": "holon.heatconsumptionasset", "pk": 444054, "fields": {"consumptionasset_ptr": 444054, "yearlyDemandHeat_kWh": 2000.0}}, {"model": "holon.heatconsumptionasset", "pk": 444061, "fields": {"consumptionasset_ptr": 444061, "yearlyDemandHeat_kWh": 2000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444020, "fields": {"consumptionasset_ptr": 444020, "yearlyDemandElectricity_kWh": 11000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444026, "fields": {"consumptionasset_ptr": 444026, "yearlyDemandElectricity_kWh": 35000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444029, "fields": {"consumptionasset_ptr": 444029, "yearlyDemandElectricity_kWh": 11000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444035, "fields": {"consumptionasset_ptr": 444035, "yearlyDemandElectricity_kWh": 11000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444041, "fields": {"consumptionasset_ptr": 444041, "yearlyDemandElectricity_kWh": 11000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444047, "fields": {"consumptionasset_ptr": 444047, "yearlyDemandElectricity_kWh": 11000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444053, "fields": {"consumptionasset_ptr": 444053, "yearlyDemandElectricity_kWh": 11000.0}}, {"model": "holon.electricconsumptionasset", "pk": 444060, "fields": {"consumptionasset_ptr": 444060, "yearlyDemandElectricity_kWh": 11000.0}}, {"model": "holon.conversionasset", "pk": 444012, "fields": {"energyasset_ptr": 444012, "type": "CURTAILER_HEAT", "eta_r": 0.0}}, {"model": "holon.conversionasset", "pk": 444014, "fields": {"energyasset_ptr": 444014, "type": "HEAT_PUMP_WATER", "eta_r": 0.5}}, {"model": "holon.conversionasset", "pk": 444015, "fields": {"energyasset_ptr": 444015, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444023, "fields": {"energyasset_ptr": 444023, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444027, "fields": {"energyasset_ptr": 444027, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444032, "fields": {"energyasset_ptr": 444032, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444038, "fields": {"energyasset_ptr": 444038, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444044, "fields": {"energyasset_ptr": 444044, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444050, "fields": {"energyasset_ptr": 444050, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444056, "fields": {"energyasset_ptr": 444056, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444057, "fields": {"energyasset_ptr": 444057, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444063, "fields": {"energyasset_ptr": 444063, "type": "GAS_BURNER", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444065, "fields": {"energyasset_ptr": 444065, "type": "METHANE_CHP", "eta_r": 0.95}}, {"model": "holon.conversionasset", "pk": 444067, "fields": {"energyasset_ptr": 444067, "type": "HEAT_PUMP_WATER", "eta_r": 0.5}}, {"model": "holon.cookingconversionasset", "pk": 444022, "fields": {"energyasset_ptr": 444022, "type": "GAS_PIT", "capacityHeat_kW": 8.0, "capacityElectricity_kW": null, "eta_r": 0.75}}, {"model": "holon.cookingconversionasset", "pk": 444031, "fields": {"energyasset_ptr": 444031, "type": "GAS_PIT", "capacityHeat_kW": 8.0, "capacityElectricity_kW": null, "eta_r": 0.75}}, {"model": "holon.cookingconversionasset", "pk": 444037, "fields": {"energyasset_ptr": 444037, "type": "GAS_PIT", "capacityHeat_kW": 8.0, "capacityElectricity_kW": null, "eta_r": 0.75}}, {"model": "holon.cookingconversionasset", "pk": 444043, "fields": {"energyasset_ptr": 444043, "type": "GAS_PIT", "capacityHeat_kW": 8.0, "capacityElectricity_kW": null, "eta_r": 0.75}}, {"model": "holon.cookingconversionasset", "pk": 444049, "fields": {"energyasset_ptr": 444049, "type": "GAS_PIT", "capacityHeat_kW": 8.0, "capacityElectricity_kW": null, "eta_r": 0.75}}, {"model": "holon.cookingconversionasset", "pk": 444055, "fields": {"energyasset_ptr": 444055, "type": "GAS_PIT", "capacityHeat_kW": 8.0, "capacityElectricity_kW": null, "eta_r": 0.75}}, {"model": "holon.cookingconversionasset", "pk": 444062, "fields": {"energyasset_ptr": 444062, "type": "GAS_PIT", "capacityHeat_kW": 8.0, "capacityElectricity_kW": null, "eta_r": 0.75}}, {"model": "holon.heatconversionasset", "pk": 444012, "fields": {"conversionasset_ptr": 444012, "deliveryTemp_degC": 0.0}}, {"model": "holon.heatconversionasset", "pk": 444014, "fields": {"conversionasset_ptr": 444014, "deliveryTemp_degC": 60.0}}, {"model": "holon.heatconversionasset", "pk": 444015, "fields": {"conversionasset_ptr": 444015, "deliveryTemp_degC": 100.0}}, {"model": "holon.heatconversionasset", "pk": 444023, "fields": {"conversionasset_ptr": 444023, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444027, "fields": {"conversionasset_ptr": 444027, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444032, "fields": {"conversionasset_ptr": 444032, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444038, "fields": {"conversionasset_ptr": 444038, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444044, "fields": {"conversionasset_ptr": 444044, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444050, "fields": {"conversionasset_ptr": 444050, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444056, "fields": {"conversionasset_ptr": 444056, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444057, "fields": {"conversionasset_ptr": 444057, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444063, "fields": {"conversionasset_ptr": 444063, "deliveryTemp_degC": 90.0}}, {"model": "holon.heatconversionasset", "pk": 444065, "fields": {"conversionasset_ptr": 444065, "deliveryTemp_degC": 100.0}}, {"model": "holon.heatconversionasset", "pk": 444067, "fields": {"conversionasset_ptr": 444067, "deliveryTemp_degC": 60.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444012, "fields": {"heatconversionasset_ptr": 444012, "capacityHeat_kW": 600.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444015, "fields": {"heatconversionasset_ptr": 444015, "capacityHeat_kW": 60.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444023, "fields": {"heatconversionasset_ptr": 444023, "capacityHeat_kW": 30.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444027, "fields": {"heatconversionasset_ptr": 444027, "capacityHeat_kW": 60.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444032, "fields": {"heatconversionasset_ptr": 444032, "capacityHeat_kW": 30.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444038, "fields": {"heatconversionasset_ptr": 444038, "capacityHeat_kW": 30.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444044, "fields": {"heatconversionasset_ptr": 444044, "capacityHeat_kW": 30.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444050, "fields": {"heatconversionasset_ptr": 444050, "capacityHeat_kW": 30.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444056, "fields": {"heatconversionasset_ptr": 444056, "capacityHeat_kW": 30.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444057, "fields": {"heatconversionasset_ptr": 444057, "capacityHeat_kW": 30.0}}, {"model": "holon.chemicalheatconversionasset", "pk": 444063, "fields": {"heatconversionasset_ptr": 444063, "capacityHeat_kW": 30.0}}, {"model": "holon.electricheatconversionasset", "pk": 444014, "fields": {"heatconversionasset_ptr": 444014, "capacityElectricity_kW": 200.0}}, {"model": "holon.electricheatconversionasset", "pk": 444067, "fields": {"heatconversionasset_ptr": 444067, "capacityElectricity_kW": 20.0}}, {"model": "holon.transportheatconversionasset", "pk": 444067, "fields": {"electricheatconversionasset_ptr": 444067, "ambientTempType": "WATER"}}, {"model": "holon.hybridheatcoversionasset", "pk": 444065, "fields": {"heatconversionasset_ptr": 444065, "ambientTempType": "AIR", "capacityHeat_kW": 10.0, "capacityElectricity_kW": 9.0}}, {"model": "holon.productionasset", "pk": 444001, "fields": {"energyasset_ptr": 444001, "type": "RESIDUALHEATHT"}}, {"model": "holon.productionasset", "pk": 444002, "fields": {"energyasset_ptr": 444002, "type": "RESIDUALHEATLT"}}, {"model": "holon.productionasset", "pk": 444010, "fields": {"energyasset_ptr": 444010, "type": "RESIDUALHEATHT"}}, {"model": "holon.productionasset", "pk": 444013, "fields": {"energyasset_ptr": 444013, "type": "RESIDUALHEATLT"}}, {"model": "holon.heatproductionasset", "pk": 444010, "fields": {"productionasset_ptr": 444010, "capacityHeat_kW": 600.0, "deliveryTemp_degC": 100.0}}, {"model": "holon.heatproductionasset", "pk": 444013, "fields": {"productionasset_ptr": 444013, "capacityHeat_kW": 300.0, "deliveryTemp_degC": 15.0}}, {"model": "holon.storageasset", "pk": 444006, "fields": {"energyasset_ptr": 444006, "type": "STORAGE_HEAT"}}, {"model": "holon.storageasset", "pk": 444009, "fields": {"energyasset_ptr": 444009, "type": "STORAGE_HEAT"}}, {"model": "holon.storageasset", "pk": 444017, "fields": {"energyasset_ptr": 444017, "type": "STORAGE_HEAT"}}, {"model": "holon.storageasset", "pk": 444018, "fields": {"energyasset_ptr": 444018, "type": "STORAGE_HEAT"}}, {"model": "holon.storageasset", "pk": 444019, "fields": {"energyasset_ptr": 444019, "type": "HEATMODEL"}}, {"model": "holon.storageasset", "pk": 444025, "fields": {"energyasset_ptr": 444025, "type": "HEATMODEL"}}, {"model": "holon.storageasset", "pk": 444028, "fields": {"energyasset_ptr": 444028, "type": "HEATMODEL"}}, {"model": "holon.storageasset", "pk": 444034, "fields": {"energyasset_ptr": 444034, "type": "HEATMODEL"}}, {"model": "holon.storageasset", "pk": 444040, "fields": {"energyasset_ptr": 444040, "type": "HEATMODEL"}}, {"model": "holon.storageasset", "pk": 444046, "fields": {"energyasset_ptr": 444046, "type": "HEATMODEL"}}, {"model": "holon.storageasset", "pk": 444052, "fields": {"energyasset_ptr": 444052, "type": "HEATMODEL"}}, {"model": "holon.storageasset", "pk": 444059, "fields": {"energyasset_ptr": 444059, "type": "HEATMODEL"}}, {"model": "holon.heatstorageasset", "pk": 444006, "fields": {"storageasset_ptr": 444006, "capacityHeat_kW": 2000.0, "minTemp_degC": 60, "maxTemp_degC": 80, "setTemp_degC": 70, "initialTemperature_degC": 70, "lossFactor_WpK": 3.0, "heatCapacity_JpK": 120000000.0, "ambientTempType": "GROUND"}}, {"model": "holon.heatstorageasset", "pk": 444009, "fields": {"storageasset_ptr": 444009, "capacityHeat_kW": 2000.0, "minTemp_degC": 70, "maxTemp_degC": 1000, "setTemp_degC": 90, "initialTemperature_degC": 90, "lossFactor_WpK": 3.0, "heatCapacity_JpK": 120000000.0, "ambientTempType": "GROUND"}}, {"model": "holon.heatstorageasset", "pk": 444017, "fields": {"storageasset_ptr": 444017, "capacityHeat_kW": 2000.0, "minTemp_degC": 70, "maxTemp_degC": 100, "setTemp_degC": 90, "initialTemperature_degC": 90, "lossFactor_WpK": 100.0, "heatCapacity_JpK": 100000.0, "ambientTempType": "GROUND"}}, {"model": "holon.heatstorageasset", "pk": 444018, "fields": {"storageasset_ptr": 444018, "capacityHeat_kW": 2000.0, "minTemp_degC": 60, "maxTemp_degC": 80, "setTemp_degC": 70, "initialTemperature_degC": 70, "lossFactor_WpK": 100.0, "heatCapacity_JpK": 1000000.0, "ambientTempType": "GROUND"}}, {"model": "holon.heatstorageasset", "pk": 444019, "fields": {"storageasset_ptr": 444019, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 80.0, "heatCapacity_JpK": 10000000.0, "ambientTempType": "AIR"}}, {"model": "holon.heatstorageasset", "pk": 444025, "fields": {"storageasset_ptr": 444025, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 80.0, "heatCapacity_JpK": 20000000.0, "ambientTempType": "AIR"}}, {"model": "holon.heatstorageasset", "pk": 444028, "fields": {"storageasset_ptr": 444028, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 60.0, "heatCapacity_JpK": 10000000.0, "ambientTempType": "AIR"}}, {"model": "holon.heatstorageasset", "pk": 444034, "fields": {"storageasset_ptr": 444034, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 50.0, "heatCapacity_JpK": 10000000.0, "ambientTempType": "AIR"}}, {"model": "holon.heatstorageasset", "pk": 444040, "fields": {"storageasset_ptr": 444040, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 70.0, "heatCapacity_JpK": 10000000.0, "ambientTempType": "AIR"}}, {"model": "holon.heatstorageasset", "pk": 444046, "fields": {"storageasset_ptr": 444046, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 70.0, "heatCapacity_JpK": 10000000.0, "ambientTempType": "AIR"}}, {"model": "holon.heatstorageasset", "pk": 444052, "fields": {"storageasset_ptr": 444052, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 70.0, "heatCapacity_JpK": 10000000.0, "ambientTempType": "AIR"}}, {"model": "holon.heatstorageasset", "pk": 444059, "fields": {"storageasset_ptr": 444059, "capacityHeat_kW": 100.0, "minTemp_degC": -10, "maxTemp_degC": 50, "setTemp_degC": 20, "initialTemperature_degC": 20, "lossFactor_WpK": 100.0, "heatCapacity_JpK": 10000000.0, "ambientTempType": "AIR"}}, {"model": "holon.contract", "pk": 444001, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444002, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444002, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444002, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444003, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444002, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444004, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444002, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444005, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444002, "energyCarrier": "ELECTRICITY", "actor": 444003, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444006, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444003, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444007, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444003, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444008, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444003, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444009, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444002, "energyCarrier": "ELECTRICITY", "actor": 444004, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444010, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444003, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444011, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444004, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444012, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444004, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444013, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444002, "energyCarrier": "ELECTRICITY", "actor": 444005, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444014, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444004, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444015, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444005, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444016, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444005, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444017, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444002, "energyCarrier": "ELECTRICITY", "actor": 444006, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444018, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444005, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444019, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444006, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444020, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444006, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444021, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444002, "energyCarrier": "ELECTRICITY", "actor": 444007, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444022, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444002, "energyCarrier": "ELECTRICITY", "actor": 444006, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444023, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444007, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444024, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444002, "energyCarrier": "ELECTRICITY", "actor": 444008, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444025, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444007, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444026, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444008, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444027, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444007, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444028, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444008, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444029, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444008, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444030, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444010, "annualFee_eur": 0.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444031, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444010, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444032, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444010, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444033, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444010, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444034, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444011, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444035, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444011, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444036, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444011, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444037, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444011, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444038, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444012, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444039, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444012, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444040, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444012, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444041, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444012, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444042, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444013, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444043, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444014, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444044, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444015, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444045, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444016, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444046, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444018, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444047, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444019, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444048, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444020, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444049, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444021, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444050, "fields": {"polymorphic_ctype": ["holon", "deliverycontract"], "contractType": "DELIVERY", "name": "", "contractScope": 444023, "energyCarrier": "ELECTRICITY", "actor": 444022, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444051, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444013, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444052, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444014, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444053, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444015, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444054, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444016, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444055, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444018, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444056, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444019, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444057, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444020, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444058, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444021, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444059, "fields": {"polymorphic_ctype": ["holon", "connectioncontract"], "contractType": "CONNECTION", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444022, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444060, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444013, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444061, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444014, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444062, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444015, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444063, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444016, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444064, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444018, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444065, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444019, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444066, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444020, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444067, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444021, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444068, "fields": {"polymorphic_ctype": ["holon", "transportcontract"], "contractType": "TRANSPORT", "name": "", "contractScope": 444001, "energyCarrier": "ELECTRICITY", "actor": 444022, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444069, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444013, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444070, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444014, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444071, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444015, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444072, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444016, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444073, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444018, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444074, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444019, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444075, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444020, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444076, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444021, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.contract", "pk": 444077, "fields": {"polymorphic_ctype": ["holon", "taxcontract"], "contractType": "TAX", "name": "", "contractScope": 444024, "energyCarrier": "ELECTRICITY", "actor": 444022, "annualFee_eur": 100.0, "wildcard_JSON": null, "is_rule_action_template": false}}, {"model": "holon.deliverycontract", "pk": 444001, "fields": {"contract_ptr": 444001, "deliveryContractType": "ELECTRICITY_VARIABLE", "deliveryPrice_eurpkWh": 0.0, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444005, "fields": {"contract_ptr": 444005, "deliveryContractType": "ELECTRICITY_VARIABLE", "deliveryPrice_eurpkWh": 0.0, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444009, "fields": {"contract_ptr": 444009, "deliveryContractType": "ELECTRICITY_VARIABLE", "deliveryPrice_eurpkWh": 0.0, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444013, "fields": {"contract_ptr": 444013, "deliveryContractType": "ELECTRICITY_VARIABLE", "deliveryPrice_eurpkWh": 0.0, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444017, "fields": {"contract_ptr": 444017, "deliveryContractType": "ELECTRICITY_VARIABLE", "deliveryPrice_eurpkWh": 0.0, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444021, "fields": {"contract_ptr": 444021, "deliveryContractType": "ELECTRICITY_VARIABLE", "deliveryPrice_eurpkWh": 0.0, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444024, "fields": {"contract_ptr": 444024, "deliveryContractType": "ELECTRICITY_VARIABLE", "deliveryPrice_eurpkWh": 0.0, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444030, "fields": {"contract_ptr": 444030, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444034, "fields": {"contract_ptr": 444034, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444038, "fields": {"contract_ptr": 444038, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444042, "fields": {"contract_ptr": 444042, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444043, "fields": {"contract_ptr": 444043, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444044, "fields": {"contract_ptr": 444044, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444045, "fields": {"contract_ptr": 444045, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444046, "fields": {"contract_ptr": 444046, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444047, "fields": {"contract_ptr": 444047, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444048, "fields": {"contract_ptr": 444048, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444049, "fields": {"contract_ptr": 444049, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.deliverycontract", "pk": 444050, "fields": {"contract_ptr": 444050, "deliveryContractType": "ELECTRICITY_FIXED", "deliveryPrice_eurpkWh": 0.25, "feedinPrice_eurpkWh": 0.0}}, {"model": "holon.connectioncontract", "pk": 444002, "fields": {"contract_ptr": 444002, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444006, "fields": {"contract_ptr": 444006, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444010, "fields": {"contract_ptr": 444010, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444014, "fields": {"contract_ptr": 444014, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444018, "fields": {"contract_ptr": 444018, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444022, "fields": {"contract_ptr": 444022, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444025, "fields": {"contract_ptr": 444025, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444026, "fields": {"contract_ptr": 444026, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444031, "fields": {"contract_ptr": 444031, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444035, "fields": {"contract_ptr": 444035, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444039, "fields": {"contract_ptr": 444039, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444051, "fields": {"contract_ptr": 444051, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444052, "fields": {"contract_ptr": 444052, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444053, "fields": {"contract_ptr": 444053, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444054, "fields": {"contract_ptr": 444054, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444055, "fields": {"contract_ptr": 444055, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444056, "fields": {"contract_ptr": 444056, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444057, "fields": {"contract_ptr": 444057, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444058, "fields": {"contract_ptr": 444058, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.connectioncontract", "pk": 444059, "fields": {"contract_ptr": 444059, "connectionContractType": "DEFAULT", "nfATO_capacity_kW": 0.0, "nfATO_starttime_h": 0.0, "nfATO_endtime_h": 0.0}}, {"model": "holon.taxcontract", "pk": 444004, "fields": {"contract_ptr": 444004, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444008, "fields": {"contract_ptr": 444008, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444012, "fields": {"contract_ptr": 444012, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444016, "fields": {"contract_ptr": 444016, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444020, "fields": {"contract_ptr": 444020, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444023, "fields": {"contract_ptr": 444023, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444029, "fields": {"contract_ptr": 444029, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444033, "fields": {"contract_ptr": 444033, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444037, "fields": {"contract_ptr": 444037, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444041, "fields": {"contract_ptr": 444041, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444069, "fields": {"contract_ptr": 444069, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444070, "fields": {"contract_ptr": 444070, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444071, "fields": {"contract_ptr": 444071, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444072, "fields": {"contract_ptr": 444072, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444073, "fields": {"contract_ptr": 444073, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444074, "fields": {"contract_ptr": 444074, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444075, "fields": {"contract_ptr": 444075, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444076, "fields": {"contract_ptr": 444076, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.taxcontract", "pk": 444077, "fields": {"contract_ptr": 444077, "taxContractType": "SALDEREN", "taxDelivery_eurpkWh": 0.12, "taxFeedin_eurpkWh": 0.12, "proportionalTax_pct": 0.21}}, {"model": "holon.transportcontract", "pk": 444003, "fields": {"contract_ptr": 444003, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444007, "fields": {"contract_ptr": 444007, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444011, "fields": {"contract_ptr": 444011, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444015, "fields": {"contract_ptr": 444015, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444019, "fields": {"contract_ptr": 444019, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444027, "fields": {"contract_ptr": 444027, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444028, "fields": {"contract_ptr": 444028, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444032, "fields": {"contract_ptr": 444032, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444036, "fields": {"contract_ptr": 444036, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444040, "fields": {"contract_ptr": 444040, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444060, "fields": {"contract_ptr": 444060, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444061, "fields": {"contract_ptr": 444061, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444062, "fields": {"contract_ptr": 444062, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444063, "fields": {"contract_ptr": 444063, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444064, "fields": {"contract_ptr": 444064, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444065, "fields": {"contract_ptr": 444065, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444066, "fields": {"contract_ptr": 444066, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444067, "fields": {"contract_ptr": 444067, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.transportcontract", "pk": 444068, "fields": {"contract_ptr": 444068, "transportContractType": "DEFAULT", "bandwidthTreshold_kW": 0.0, "bandwidthTariff_eurpkWh": 0.0}}, {"model": "holon.relationattributefilter", "pk": 444004, "fields": {"polymorphic_ctype": ["holon", "relationattributefilter"], "model_attribute": "id", "comparator": "EQUAL", "value": "E14", "rule": 444003, "relation_field": "parent_electric", "relation_field_subtype": ""}}, {"model": "holon.interactiveelement", "pk": 444003, "fields": {"scenario": 444001, "name": "Buurt 1: Warmtesysteemkeuze", "type": "single_select", "level": null, "more_information": "Welke warmtesysteem voor buurt \"Oud Centrum\"?", "link_wiki_page": null}}, {"model": "holon.interactiveelementoptions", "pk": 444007, "fields": {"sort_order": 0, "input": 444003, "option": "cv_ketels", "label": "Referentie (gasketels)", "default": true, "legal_limitation": null, "level": "local", "color": null, "link_wiki_page": null}}, {"model": "holon.interactiveelementoptions", "pk": 444008, "fields": {"sort_order": 1, "input": 444003, "option": "all_electric", "label": "All-electric warmtepompen (individueel)", "default": false, "legal_limitation": null, "level": "local", "color": null, "link_wiki_page": null}}, {"model": "holon.queryandconvertconfig", "pk": 444001, "fields": {"scenario": 444001, "module": "upscaling", "name": "National upscaling", "api_url": "https://beta-engine.energytransitionmodel.com/api/v3/scenarios/", "etm_scenario_id": 123456}}, {"model": "holon.queryandconvertconfig", "pk": 444002, "fields": {"scenario": 444001, "module": "cost", "name": "Gebiedskosten", "api_url": "https://beta-engine.energytransitionmodel.com/api/v3/scenarios/", "etm_scenario_id": 123456}}, {"model": "holon.queryandconvertconfig", "pk": 444003, "fields": {"scenario": 444001, "module": "costbenefit", "name": "National upscaling", "api_url": "https://beta-engine.energytransitionmodel.com/api/v3/scenarios/", "etm_scenario_id": 123456}}, {"model": "holon.queryandconvertconfig", "pk": 444004, "fields": {"scenario": 444001, "module": "costbenefit", "name": "Cost module", "api_url": "https://beta-engine.energytransitionmodel.com/api/v3/scenarios/", "etm_scenario_id": 123456}}, {"model": "holon.etmquery", "pk": 444001, "fields": {"internal_key": "energy_hub_installed_capacity_wind_turbines_on_land", "endpoint": "input", "data_type": "value", "etm_key": "capacity_of_energy_power_wind_turbine_inland", "related_config": 444001, "related_interactive_element": null, "interactive_upscaling_comment": null}}, {"model": "holon.etmquery", "pk": 444002, "fields": {"internal_key": "1", "endpoint": "input", "data_type": "value", "etm_key": "1", "related_config": 444002, "related_interactive_element": null, "interactive_upscaling_comment": null}}, {"model": "holon.etmquery", "pk": 444003, "fields": {"internal_key": "capacity_of_energy_power_wind_turbine_inland", "endpoint": "input", "data_type": "value", "etm_key": "capacity_of_energy_power_wind_turbine_inland", "related_config": 444003, "related_interactive_element": null, "interactive_upscaling_comment": null}}, {"model": "holon.etmquery", "pk": 444004, "fields": {"internal_key": "price_of_natural_gas_per_mwh", "endpoint": "input", "data_type": "value", "etm_key": "price_of_natural_gas_per_mwh", "related_config": 444004, "related_interactive_element": null, "interactive_upscaling_comment": null}}, {"model": "holon.anylogiccloudconfig", "pk": 444001, "fields": {"api_key": "9f281fab-a0bf-4bf5-9baa-b74d9d2fcc89", "url": "https://engine.holontool.nl", "model_name": "Base_29mar", "model_version_number": 1, "scenario": 444001, "owner_email": "jorrit.van.den.houten@witteveenbos.com"}}, {"model": "holon.anylogiccloudinput", "pk": 444001, "fields": {"anylogic_key": "P import local config jsons", "anylogic_value": false, "anylogic_model_configuration": 444001}}, {"model": "holon.anylogiccloudoutput", "pk": 444001, "fields": {"anylogic_key": "O output actorData", "internal_key": "actors", "anylogic_model_configuration": 444001}}, {"model": "holon.anylogiccloudoutput", "pk": 444002, "fields": {"anylogic_key": "O simulation results", "internal_key": "simulation_results", "anylogic_model_configuration": 444001}}, {"model": "holon.anylogiccloudoutput", "pk": 444003, "fields": {"anylogic_key": "O hourly curves data", "internal_key": "curves", "anylogic_model_configuration": 444001}}, {"model": "holon.anylogiccloudoutput", "pk": 444004, "fields": {"anylogic_key": "O output runSettings", "internal_key": "run_settings", "anylogic_model_configuration": 444001}}, {"model": "holon.rule", "pk": 444003, "fields": {"polymorphic_ctype": ["holon", "scenariorule"], "model_type": "GridConnection", "model_subtype": "HouseGridConnection"}}, {"model": "holon.scenariorule", "pk": 444003, "fields": {"rule_ptr": 444003, "interactive_element_option": 444008, "interactive_element_continuous_values": null}}, {"model": "holon.policy", "pk": 444002, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Grid_MS_congestion_allowance_level_kW", "value": "0", "unit": "kW", "comment": "gridOperator policy variable", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444003, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Grid_MS_congestion_price_eurpkWh", "value": "10.0", "unit": "eurpkWh", "comment": "gridOperator policy value", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444004, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Grid_MS_congestion_threshold_fr", "value": "0.1", "unit": "fr", "comment": "gridOperator policy value", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444005, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Grid_MS_congestion_pricing_consumption_eurpkWh", "value": "TRUE", "unit": "null", "comment": "gridOperator policy value", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444006, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Grid_MS_congestion_pricing_production_eurpkWh", "value": "TRUE", "unit": "null", "comment": "gridOperator policy value", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444007, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Fixed_electricity_price_eurpkWh", "value": "0.21", "unit": "EUR p kWh", "comment": "Fixed_electricity_price", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444008, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Fixed_heat_price_eurpkWh", "value": "0.1", "unit": "EUR p kWh", "comment": "Fixed_heat_price", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444009, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Fixed_methane_price_eurpkWh", "value": "0.05", "unit": "EUR p kWh", "comment": "Fixed_methane_price", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444010, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Fixed_hydrogen_price_eurpkWh", "value": "0.3", "unit": "EUR p kWh", "comment": "Fixed_hydrogen_price", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444011, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Energy_supplier_electricity_price_margin_eurpkWh", "value": "0.17", "unit": "fr", "comment": "p_variableElectricityPriceOverNational_eurpkWh", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444012, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Fixed_electricity_feed_in_tariff_eurpkWh", "value": "0.1", "unit": "EUR_pKWh", "comment": "p_fixedFeedinTariff_eurpkWh", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444013, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Fixed_diesel_price_eurpkWh", "value": "0.2", "unit": "EUR_pKWh", "comment": "Fixed_diesel_price", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444014, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Time_buffer_for_spread_charging_min", "value": "60", "unit": "minutes", "comment": "Time_buffer_for_spread_charging, Integer value", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444015, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Salderen", "value": "false", "unit": "boolean", "comment": "switch for salderen", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444016, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Capacitypricing_households_kW", "value": "5", "unit": "int", "comment": "power level at which capacity pricing kicks in", "payload": 444001, "wildcard_JSON": null}}, {"model": "holon.policy", "pk": 444017, "fields": {"polymorphic_ctype": ["holon", "policy"], "parameter": "Capacitypricing_households_eur", "value": "0.5", "unit": "float", "comment": "capacity price value for households", "payload": 444001, "wildcard_JSON": null}}] \ No newline at end of file diff --git a/src/holon/fixtures/utils/reset_pk_fk_ptr.py b/src/holon/fixtures/utils/reset_pk_fk_ptr.py index 0ec6cadb9..2a0a7ccb7 100644 --- a/src/holon/fixtures/utils/reset_pk_fk_ptr.py +++ b/src/holon/fixtures/utils/reset_pk_fk_ptr.py @@ -3,10 +3,10 @@ # fp = "../peter-dupliceter-datamodel-fixture.json" # fp_out = "../peter-dupliceter-datamodel-fixture_clean_keys.json" -fp = "../jorrit/ref/tvw-POSTSCALEUP.json" -fp_out = "../jorrit/ref/tvw-POSTCLEANUP.json" +fp = "../jorrit/ref/tvw-PRESCALEUP.json" +fp_out = "../jorrit/ref/tvw-CLEANSMALL.json" -BASE_INT = 456000 # change me! +BASE_INT = 444000 # change me! relations = set( [ @@ -26,6 +26,7 @@ "pk", "related_config", "related_interactive_element", + "rule", "scenario", "subgroup", ] From 8a32ae2ef65ea1b4dc93589755c68f97d18243d8 Mon Sep 17 00:00:00 2001 From: "WBAD\\TAVM" Date: Tue, 25 Apr 2023 11:33:13 +0200 Subject: [PATCH 20/29] add model field --- src/holon/models/interactive_element.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/holon/models/interactive_element.py b/src/holon/models/interactive_element.py index 5f434be65..78c9a48ed 100644 --- a/src/holon/models/interactive_element.py +++ b/src/holon/models/interactive_element.py @@ -183,6 +183,14 @@ class InteractiveElementContinuousValues(ClusterableModel): default=100, help_text=_("Maximum amount of the continuous input"), ) + discretization_steps = models.IntegerField( + null=True, + blank=True, + default=5, + help_text=_( + "Number of steps the slider has. Leave empty or 0 to let the slider be contiuous." + ), + ) slider_unit = models.ForeignKey( InteractiveElementUnit, null=True, @@ -195,6 +203,7 @@ class InteractiveElementContinuousValues(ClusterableModel): FieldPanel("slider_value_default"), FieldPanel("slider_value_min"), FieldPanel("slider_value_max"), + FieldPanel("discretization_steps"), InlinePanel("rules", heading="Rules", label="Rules"), FieldPanel("slider_unit"), ] From dfd5671aaf860824998404fcc7fb737b5647f936 Mon Sep 17 00:00:00 2001 From: "WBAD\\TAVM" Date: Tue, 25 Apr 2023 12:25:53 +0200 Subject: [PATCH 21/29] migration --- ...ntcontinuousvalues_discretization_steps.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/holon/migrations/0038_interactiveelementcontinuousvalues_discretization_steps.py diff --git a/src/holon/migrations/0038_interactiveelementcontinuousvalues_discretization_steps.py b/src/holon/migrations/0038_interactiveelementcontinuousvalues_discretization_steps.py new file mode 100644 index 000000000..a758c3018 --- /dev/null +++ b/src/holon/migrations/0038_interactiveelementcontinuousvalues_discretization_steps.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.8 on 2023-04-21 08:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("holon", "0037_alter_contract_actor_alter_contract_contractscope"), + ] + + operations = [ + migrations.AddField( + model_name="interactiveelementcontinuousvalues", + name="discretization_steps", + field=models.IntegerField( + blank=True, + default=5, + help_text="Number of steps the slider has. Leave empty or 0 to let the slider be contiuous.", + null=True, + ), + ), + ] From 2da172d68279f5522daca9a23954cb8c59792374 Mon Sep 17 00:00:00 2001 From: "WBAD\\TAVM" Date: Tue, 25 Apr 2023 12:31:04 +0200 Subject: [PATCH 22/29] frontend --- .../InteractiveImage/ImageSlider.tsx | 52 ++++++++++++++++--- .../InteractiveInputs/InteractiveInputs.tsx | 6 ++- src/main/blocks/storyline_section.py | 1 + 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/frontend/components/InteractiveImage/ImageSlider.tsx b/frontend/components/InteractiveImage/ImageSlider.tsx index d35d1adb6..f95de7120 100644 --- a/frontend/components/InteractiveImage/ImageSlider.tsx +++ b/frontend/components/InteractiveImage/ImageSlider.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import InteractiveInputPopover from "../InteractiveInputs/InteractiveInputPopover"; import styles from "./ImageSlider.module.css"; @@ -40,6 +40,43 @@ export default function ImageSlider({ selectedLevel, }: Props) { const [sliderValue, setSliderValue] = useState(defaultValue); + const [realValue, setRealValue] = useState(defaultValue); + const [sliderTooltipPosition, setSliderTooltipPosition] = useState(defaultValue); + + const slidermin = step ? 0 : min; + const slidermax = step ? step - 1 : max; + const sliderstep = 1; + + useEffect(() => { + //set slider tooltip position based upon defaulvalue, maxvalue, minvalue + //if minvalue == 10, maxvalue ==100, default == 55, then the sliderposition should be: + // (55-10) / (100 / 10) == (50 percent) + + // because of the the Discretization steps, there are two values: + // 1: slidervalue: this is value that is being used to position the slider. This is nessecary because a input type range can't handle fractions such as 1/3 + // 2: realvalue: this is the actual value, that is being used in the calculattions + + // if steps == 6 , the slider is a slider from 0 - 6. + // the value of the slider is being transformed to an actual value, based upon the formula + + // (slidervalue - min) / (max-min) * slidermax + // if the slider is value 3, the calculation is + // (3-0) / (6-0) * 6 == 3 + + setSliderTooltipPosition((defaultValue - min) / (max - min)); + setSliderValue(((defaultValue - min) / (max - min)) * slidermax); + }, []); + + function updateSliderValue(inputId, slidervalue) { + const actualValue = Math.floor((slidervalue / slidermax) * (max - min) + min); + + setSliderValue(slidervalue); + setRealValue(actualValue); + setSliderTooltipPosition(slidervalue / slidermax); + + setValue(inputId, actualValue); + } + return (
@@ -67,15 +104,14 @@ export default function ImageSlider({ disabled={locked} value={sliderValue} onChange={e => { - setSliderValue(Number(e.target.value)); - setValue(inputId, Number(e.target.value)); + updateSliderValue(inputId, Number(e.target.value)); }} className={`h-1 w-3/5 ${locked ? "cursor-not-allowed" : ""} ${ styles.slider } interactImg appearance-none disabled:bg-holon-grey-300`} - step={step} - min={min} - max={max} + step={sliderstep} + min={slidermin} + max={slidermax} type={type} id={inputId + (selectedLevel ? "holarchy" : "storyline")} /> @@ -84,8 +120,8 @@ export default function ImageSlider({
- {sliderValue} + style={{ left: "calc((" + sliderTooltipPosition + ") * 100%)" }}> + {realValue}
diff --git a/frontend/components/InteractiveInputs/InteractiveInputs.tsx b/frontend/components/InteractiveInputs/InteractiveInputs.tsx index 9593fc6c6..f4b7bb76e 100644 --- a/frontend/components/InteractiveInputs/InteractiveInputs.tsx +++ b/frontend/components/InteractiveInputs/InteractiveInputs.tsx @@ -31,6 +31,7 @@ export type InteractiveInputOptions = { sliderValueDefault?: number; sliderValueMax?: number; sliderValueMin?: number; + discretizationSteps?: number; sliderUnit?: string; level?: string; }; @@ -55,17 +56,18 @@ function InteractiveInputs({ : options; //if there is a selectedlevel, it should match, the slider + return type === "continuous" && (!selectedLevel || selectedLevel.toLowerCase() == level?.toLowerCase()) ? ( Date: Tue, 25 Apr 2023 12:01:45 +0000 Subject: [PATCH 23/29] fix interactive image with new imageslider --- .../components/InteractiveImage/InteractiveImage.test.tsx | 8 ++++---- frontend/components/InteractiveImage/InteractiveImage.tsx | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/frontend/components/InteractiveImage/InteractiveImage.test.tsx b/frontend/components/InteractiveImage/InteractiveImage.test.tsx index 1eaf76ac4..903a70e69 100644 --- a/frontend/components/InteractiveImage/InteractiveImage.test.tsx +++ b/frontend/components/InteractiveImage/InteractiveImage.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, fireEvent } from "@testing-library/react"; +import { fireEvent, render, screen } from "@testing-library/react"; import { act } from "react-dom/test-utils"; import InteractiveImage from "./InteractiveImage"; @@ -23,7 +23,7 @@ describe("Interactive Image", () => { }); it("windforce is set to 3", () => { - expect(screen.getByTestId("windforceSlider").value).toBe("3"); + expect(screen.getByTestId("windforceSlider").value).toBe("1"); }); }); @@ -62,7 +62,7 @@ describe("slider changes image", () => { it("windmills will speed up when slider is moved right", async () => { await act(async () => { - fireEvent.change(screen.getByTestId("windforceSlider"), { target: { value: 12 } }); + fireEvent.change(screen.getByTestId("windforceSlider"), { target: { value: 4 } }); }); expect(document.getElementById("dataDiv")).toHaveAttribute("data-windforce", "12"); }); @@ -71,6 +71,6 @@ describe("slider changes image", () => { await act(async () => { fireEvent.change(screen.getByTestId("windforceSlider"), { target: { value: 3 } }); }); - expect(document.getElementById("dataDiv")).toHaveAttribute("data-windforce", "3"); + expect(document.getElementById("dataDiv")).toHaveAttribute("data-windforce", "9"); }); }); diff --git a/frontend/components/InteractiveImage/InteractiveImage.tsx b/frontend/components/InteractiveImage/InteractiveImage.tsx index 908909fa6..38855a3f9 100644 --- a/frontend/components/InteractiveImage/InteractiveImage.tsx +++ b/frontend/components/InteractiveImage/InteractiveImage.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; -import ImageSlider from "./ImageSlider"; import ImgFlatSolar from "./ImageElements/ImgFlatSolar"; +import ImageSlider from "./ImageSlider"; export default function InteractiveImage() { const [solarpanels, setSolarpanels] = useState(0); @@ -23,7 +23,6 @@ export default function InteractiveImage() { setValue={(id, value) => setSolarpanels(value)} min={0} max={6} - step={1} label="Aantal zonnepanelen" type="range">

@@ -36,7 +35,6 @@ export default function InteractiveImage() { setValue={(id, value) => setWindmills(value)} min={0} max={3} - step={1} label="Aantal windmolens" type="range">

Bepaal hier hoe hard de wind waait.

@@ -47,7 +45,7 @@ export default function InteractiveImage() { setValue={(id, value) => setWindForce(value)} min={0} max={12} - step={3} + step={5} // 0 3 6 9 12 label="Windkracht" type="range">
From 8d5925967d90057f189e556c2f1372c2f39cff13 Mon Sep 17 00:00:00 2001 From: Erik van Velzen Date: Tue, 25 Apr 2023 16:07:39 +0200 Subject: [PATCH 24/29] sentry: downgrade The build tool Hatch could resolve dependencies of Sentry 1.20.0 so downgrade to 1.19.1 --- src/requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requirements/base.txt b/src/requirements/base.txt index 90b3f3dac..9f8b3b516 100644 --- a/src/requirements/base.txt +++ b/src/requirements/base.txt @@ -2,7 +2,7 @@ Django>=4.1,<4.2 boto3>1.19,<1.25 django-storages==1.13 psycopg2==2.9.3 -sentry_sdk==1.20.0 +sentry_sdk==1.19.1 python-dotenv==0.21 wagtail>=4.1,<4.2 wagtail-meta-preview From 2ee4661f9c61756e0fc46abb90fdca7a36d88046 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Tue, 25 Apr 2023 14:46:14 +0000 Subject: [PATCH 25/29] merge migration and rebase main --- src/holon/migrations/0039_merge_20230425_1645.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/holon/migrations/0039_merge_20230425_1645.py diff --git a/src/holon/migrations/0039_merge_20230425_1645.py b/src/holon/migrations/0039_merge_20230425_1645.py new file mode 100644 index 000000000..5c6d5b377 --- /dev/null +++ b/src/holon/migrations/0039_merge_20230425_1645.py @@ -0,0 +1,12 @@ +# Generated by Django 4.1.8 on 2023-04-25 14:45 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("holon", "0038_genericetmquery_etmquery_interactive_upscaling_title_and_more"), + ("holon", "0038_interactiveelementcontinuousvalues_discretization_steps"), + ] + + operations = [] From 54c8f3cf41e6c336949a4345deb9a8b677101733 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Tue, 25 Apr 2023 14:58:41 +0000 Subject: [PATCH 26/29] remove bad boi print statement --- src/holon/services/costs_table.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/holon/services/costs_table.py b/src/holon/services/costs_table.py index 0cd616979..276994816 100644 --- a/src/holon/services/costs_table.py +++ b/src/holon/services/costs_table.py @@ -107,7 +107,6 @@ def __init__(self, to_actor, from_actor, price) -> None: self.from_actor = from_actor self.to_actor = to_actor self.price = price - print(f"CostItem: {self.from_group()} -> {self.to_group()} = {self.price}") def from_group(self): return CostItem.group(self.from_actor) From 6862718edd09873ca00dfefccebc3753d4588684 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Tue, 25 Apr 2023 15:11:09 +0000 Subject: [PATCH 27/29] fix rebase/merge issue --- src/main/blocks/storyline_section.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/blocks/storyline_section.py b/src/main/blocks/storyline_section.py index 37fc8d5ad..27c80ac7b 100644 --- a/src/main/blocks/storyline_section.py +++ b/src/main/blocks/storyline_section.py @@ -33,11 +33,6 @@ def get_queryset(self, request): from main.pages.casus import CasusPage qs = super().get_queryset(request) - - # Send all interactive elements as queryset if the interactive element is linked outside of the pages - if request.META.get("HTTP_REFERER").find("pages") == -1: - return qs - casus_id = request.META.get("HTTP_REFERER").split("/")[-2] if casus_id == "edit": From 8c120bd9cfb81e718a26d7e3a5aeb831c804ae98 Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Tue, 25 Apr 2023 15:53:31 +0000 Subject: [PATCH 28/29] adds reverse relations and netto cost --- src/holon/services/costs_table.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/holon/services/costs_table.py b/src/holon/services/costs_table.py index 276994816..03069e622 100644 --- a/src/holon/services/costs_table.py +++ b/src/holon/services/costs_table.py @@ -43,6 +43,7 @@ def table(self, cost_items): self._table = {} for item in cost_items: self.__add_to_table(item) + self.__add_to_table(CostItem.reversed(item)) self.__fill_out_table() def __add_to_table(self, item): @@ -65,7 +66,7 @@ def __add_from_group(self, item): """ self._table[self.__name_from(item)] = { self.__name_to(item): item.price, - self.__name_from(item): None, + self.__name_from(item): 0.0, } def __fill_out_table(self): @@ -74,6 +75,9 @@ def __fill_out_table(self): basic = {key: 0.0 for key in all_groups} for group in all_groups: self._table[group] = basic | self._table.get(group, {}) + self._table[group]["Netto kosten"] = sum( + (value for value in self._table[group].values() if value is not None) + ) def __name_from(self, item): return ( @@ -177,3 +181,12 @@ def from_dict(cls, obj: dict, actors: ActorWrapper): actors.find(obj["contractHolder"]), CostItem.price_for(obj), ) + + @classmethod + def reversed(cls, obj: "CostItem"): + """Takes a CostItem returns a new CostItem with the from and to actors switched and the price negated""" + return cls( + to_actor=obj.from_actor, + from_actor=obj.to_actor, + price=-obj.price, + ) From 4434054b51c390969e8b4d80215c004a9bc753eb Mon Sep 17 00:00:00 2001 From: thesethtruth Date: Wed, 26 Apr 2023 09:18:50 +0000 Subject: [PATCH 29/29] fix formatting --- src/holon/services/cloudclient/client.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/holon/services/cloudclient/client.py b/src/holon/services/cloudclient/client.py index 933aa28d9..c2eca217c 100644 --- a/src/holon/services/cloudclient/client.py +++ b/src/holon/services/cloudclient/client.py @@ -100,7 +100,6 @@ def outputs(self, anylogic_outputs: SingleRunOutputs): } - class PatchedAnyLogicCloudClient(ALCloudClient): """Patched version of the AnyLogic Cloud Client. @@ -113,4 +112,4 @@ class PatchedAnyLogicCloudClient(ALCloudClient): def get_model_by_name(self, name: str) -> Model: response = self._http_client.api_request("models/name/" + name) model = Model.from_json(response) - return model \ No newline at end of file + return model