@@ -32,8 +32,8 @@ class NkCost:
3232 is_meta = False
3333 is_special = False
3434
35- def __init__ (self , report : "NkReportGenerator" , cost_config : dict ):
36- self .report = report
35+ def __init__ (self , report_generator : "NkReportGenerator" , cost_config : dict ):
36+ self .generator = report_generator
3737 self .name = cost_config .get ("name" )
3838 self .billing_group = cost_config .get ("billing_group" , self .name )
3939 self .total_values = {}
@@ -44,11 +44,11 @@ def __init__(self, report: "NkReportGenerator", cost_config: dict):
4444
4545 def add_value_type (self , kind : NkCostValueType , name : str , unit : str ):
4646 self ._add_value_type_to_dict (self .total_values , kind , name , unit )
47- for ru in self .report .rental_units :
47+ for ru in self .generator .rental_units :
4848 if ru .id not in self .rental_unit_values :
4949 self .rental_unit_values [ru .id ] = {}
5050 self ._add_value_type_to_dict (self .rental_unit_values [ru .id ], kind , name , unit )
51- for section in self .report .sections :
51+ for section in self .generator .sections :
5252 if section .id not in self .section_values :
5353 self .section_values [section .id ] = {}
5454 self ._add_value_type_to_dict (self .section_values [section .id ], kind , name , unit )
@@ -58,29 +58,28 @@ def _add_value_type_to_dict(
5858 ):
5959 if kind in container :
6060 raise ValueError (f"Es existiert bereits ein Wert vom gleichen Typ wie { name } " )
61- container [kind ] = self .value_cls (name , unit , 0 , self .report .num_months * [0 ])
61+ container [kind ] = self .value_cls (name , unit , 0 , self .generator .num_months * [0 ])
6262
6363 def load_input_data (self ):
6464 pass
65- # raise NotImplementedError("load_input_data() must be implemented by subclasses")
6665
6766 def normalize_monthly_amounts (self ):
6867 """Set monthly values from annual value, or vice versa, depending on which is available."""
6968 self ._normalize_monthly_amounts_for_dict (self .total_values )
70- for ru in self .report .rental_units :
69+ for ru in self .generator .rental_units :
7170 self ._normalize_monthly_amounts_for_dict (self .rental_unit_values [ru .id ])
72- for section in self .report .sections :
71+ for section in self .generator .sections :
7372 self ._normalize_monthly_amounts_for_dict (self .section_values [section .id ])
7473
7574 def _normalize_monthly_amounts_for_dict (self , container : dict , value_required = False ):
7675 for _kind , value in container .items ():
7776 # pprint(value)
7877 total = None
7978 if value .monthly_amounts :
80- if len (value .monthly_amounts ) != self .report .num_months :
79+ if len (value .monthly_amounts ) != self .generator .num_months :
8180 raise ValueError (
8281 f"Inkonsistente Anzahl der Monatswerte { len (value .monthly_amounts )} "
83- f"und Anzahl der Monate { self .report .num_months } für { value .name } /{ _kind } "
82+ f"und Anzahl der Monate { self .generator .num_months } für { value .name } /{ _kind } "
8483 )
8584 total = sum (value .monthly_amounts )
8685 if value .amount :
@@ -94,8 +93,8 @@ def _normalize_monthly_amounts_for_dict(self, container: dict, value_required=Fa
9493 else :
9594 # Set monthly values from annual value
9695 value .monthly_amounts = [
97- value .amount / self .report .num_months
98- ] * self .report .num_months
96+ value .amount / self .generator .num_months
97+ ] * self .generator .num_months
9998 elif total :
10099 # Set annual value from monthly values
101100 value .amount = total
@@ -115,13 +114,16 @@ def split_costs(self):
115114 else 0
116115 )
117116 self ._calculate_amounts (self .total_values , kind , amount_per_weight )
118- for ru in self .report .rental_units :
117+ for ru in self .generator .rental_units :
119118 self ._calculate_amounts (self .rental_unit_values [ru .id ], kind , amount_per_weight )
120- for section in self .report .sections :
119+ for section in self .generator .sections :
121120 self ._calculate_amounts (self .section_values [section .id ], kind , amount_per_weight )
122121
122+ def update (self ):
123+ pass
124+
123125 def _calculate_amounts (self , values , kind : NkCostValueType , amount_per_weight ):
124- for month in range (self .report .num_months ):
126+ for month in range (self .generator .num_months ):
125127 amount = amount_per_weight * values [NkCostValueType .WEIGHT ].monthly_amounts [month ]
126128 if (
127129 values [kind ].monthly_amounts [month ]
@@ -148,35 +150,51 @@ def _calculate_weights(self):
148150 monthly_weights = self .get_monthly_weights ()
149151 section_weights = self .get_section_weights ()
150152 total = self .total_values [NkCostValueType .WEIGHT ]
151- for ru in self .report .rental_units :
153+ for ru in self .generator .rental_units :
152154 ru_weights = self .get_rental_unit_weights (ru .id )
153155 values = self .rental_unit_values [ru .id ][NkCostValueType .WEIGHT ]
154156 section = self .section_values [ru .section .id ][NkCostValueType .WEIGHT ]
155- for month in range (self .report .num_months ):
157+ for month in range (self .generator .num_months ):
156158 weight = (
157159 monthly_weights [month ] * section_weights [ru .section .id ] * ru_weights [month ]
158160 )
159161 values .monthly_amounts [month ] = weight
160162 section .monthly_amounts [month ] += weight
161163 total .monthly_amounts [month ] += weight
162164 values .amount = sum (values .monthly_amounts )
163- for section in self .report .sections :
165+ for section in self .generator .sections :
164166 self .section_values [section .id ][NkCostValueType .WEIGHT ].amount = sum (
165167 self .section_values [section .id ][NkCostValueType .WEIGHT ].monthly_amounts
166168 )
167169 total .amount = sum (total .monthly_amounts )
168170
171+ def _aggregate_monthly_amounts (self , value_type : NkCostValueType = NkCostValueType .COST ):
172+ """Aggregate pre-calculated monthly per-rental-unit costs up to sections and total."""
173+ for ru in self .generator .rental_units :
174+ for month in range (self .generator .num_months ):
175+ amount = self .rental_unit_values [ru .id ][value_type ].monthly_amounts [month ]
176+ self .section_values [ru .section .id ][value_type ].monthly_amounts [month ] += amount
177+ self .total_values [value_type ].monthly_amounts [month ] += amount
178+
179+ for section in self .generator .sections :
180+ self .section_values [section .id ][value_type ].amount = sum (
181+ self .section_values [section .id ][value_type ].monthly_amounts
182+ )
183+ self .total_values [value_type ].amount = sum (self .total_values [value_type ].monthly_amounts )
184+
169185 def get_monthly_weights (self ):
170186 """Default with equal weights for all months."""
171- return self .report .num_months * [1.0 ]
187+ return self .generator .num_months * [1.0 ]
172188
173189 def get_section_weights (self ):
174190 """Return weights per section, using the configured section_weights profile if available."""
175191 weight_profile = (
176- self .report .section_weights .get (self .section_weights ) if self .section_weights else None
192+ self .generator .section_weights .get (self .section_weights )
193+ if self .section_weights
194+ else None
177195 )
178196 weights = {}
179- for section in self .report .sections :
197+ for section in self .generator .sections :
180198 if weight_profile is not None :
181199 weights [section .id ] = weight_profile .get (section .id .capitalize ())
182200 else :
@@ -185,11 +203,11 @@ def get_section_weights(self):
185203
186204 def get_rental_unit_weights (self , ru_id ):
187205 """Default with equal weights for all rental units."""
188- ru = self .report .get_rental_unit_by_id (ru_id )
206+ ru = self .generator .get_rental_unit_by_id (ru_id )
189207 if ru .is_virtual :
190- return self .report .num_months * [0.0 ]
208+ return self .generator .num_months * [0.0 ]
191209 else :
192- return self .report .num_months * [1.0 ]
210+ return self .generator .num_months * [1.0 ]
193211
194212 def get_export_cost_row (self , include_percent = False ):
195213 row = self ._get_export_row (NkCostValueType .COST , include_percent )
@@ -206,9 +224,9 @@ def _get_export_row(self, kind, include_percent):
206224 row .append ("" ) # No total
207225 else :
208226 row .append (self .total_values [kind ].amount )
209- for section in self .report .sections :
227+ for section in self .generator .sections :
210228 row .append (self .section_values [section .id ][kind ].amount )
211- for ru in self .report .rental_units :
229+ for ru in self .generator .rental_units :
212230 row .append (self .rental_unit_values [ru .id ][kind ].amount )
213231 return row
214232
@@ -237,3 +255,24 @@ def get_extra_context(self, ru: "NkRentalUnit", contract: "NkContract") -> dict:
237255 return {}
238256
239257 # def update_context(self, context, ru, contract):
258+
259+
260+ class NkMeasurementDataMixin :
261+ """Mixin for NkCosts that require measurement data."""
262+
263+ def __init__ (self , report_generator : "NkReportGenerator" , cost_config : dict ):
264+ super ().__init__ (report_generator , cost_config )
265+ self .measurements = {}
266+ measurements_configs = cost_config .get ("measurement_data" )
267+ if measurements_configs :
268+ for key , config in measurements_configs .items ():
269+ self .measurements [key ] = config ["class" ](report_generator , config )
270+
271+ def load_input_data (self ):
272+ if self .measurements :
273+ for m in self .measurements .values ():
274+ m .load ()
275+ for warning in m .warnings :
276+ print (warning )
277+ self .generator .add_warning (warning [0 ], warning [1 ])
278+ super ().load_input_data ()
0 commit comments