Exemplo n.º 1
0
    def calculate(self):
        '''
        calculate the migration
        '''
        if not self.ui.recalculate_inhabitants_check.isChecked():
            self.add_layer(toggle_if_exists=True)
            return
        sum_ew = sum(x or 0 for x in self.areas.values('ew'))
        if sum_ew == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Es wurden keine definierten Teilflächen mit '
                'der Nutzungsart "Wohnen" gefunden.')
            return

        job = EwMigrationCalculation(self.project)

        def on_close():
            self.changed.emit()
            if not self.dialog.success:
                self.wanderung.table.truncate()
                self.ui.recalculate_inhabitants_check.setVisible(False)
                self.ui.recalculate_inhabitants_check.setChecked(True)
                return
            self.ui.recalculate_inhabitants_check.setVisible(True)
            self.ui.recalculate_inhabitants_check.setChecked(False)
            self.add_layer()
            self.setup_params()

        self.dialog = ProgressDialog(job, parent=self.ui, on_close=on_close)
        self.dialog.show()
Exemplo n.º 2
0
    def clone_project(self):
        '''
        clone the currently selected project
        '''
        project = self.project_manager.active_project
        if not project:
            return
        name = f'{project.name}_kopie'
        existing_names = [p.name for p in self.project_manager.projects]
        while True:
            name, ok = QInputDialog.getText(self.ui,
                                            f'{project.name} kopieren',
                                            'Name des neuen Projekts',
                                            text=name)
            if ok:
                if name in existing_names:
                    QMessageBox.warning(
                        self.ui, 'Hinweis', 'Ein Projekt mit diesem Namen ist '
                        'bereits vorhanden')
                    continue

                job = CloneProject(name, project, parent=self.ui)

                def on_success(project):
                    self.ui.project_combo.addItem(project.name, project)
                    self.ui.project_combo.setCurrentIndex(
                        self.ui.project_combo.count() - 1)
                    self.project_manager.active_project = project

                dialog = ProgressDialog(job,
                                        parent=self.ui,
                                        on_success=on_success)
                dialog.show()
            break
    def kostenvergleich(self):
        '''
        calculate the total costs and show a comparison to mean values as a bar
        chart.
        only executable if all areas have either housing or commerce as type of
        use
        '''
        types_of_use = [area.nutzungsart for area in self.areas
                        if area.nutzungsart != Nutzungsart.UNDEFINIERT.value]
        if ((Nutzungsart.WOHNEN.value not in types_of_use and
            Nutzungsart.GEWERBE.value not in types_of_use) or
            len(np.unique(types_of_use)) != 1):
            QMessageBox.warning(
                self.ui, 'Hinweis', 'Die Funktion steht nur für Projekte zur '
                'Verfügung, bei denen alle Teilflächen '
                'ausschließlich die Nutzung Wohnen bzw. Gewerbe haben.'
            )
            return

        job = GesamtkostenErmitteln(self.project)

        def on_close():
            if not self.dialog.success:
                return
            if types_of_use[0] == Nutzungsart.WOHNEN.value:
                diagram = VergleichWEDiagramm(project=self.project)
            else:
                diagram = VergleichAPDiagramm(project=self.project)
            diagram.draw()

        self.dialog = ProgressDialog(job, parent=self.ui, on_close=on_close,
                                     auto_close=True)
        self.dialog.show()
Exemplo n.º 4
0
    def calculate_nodes(self):
        '''
        calculate the traffic nodes. resets all nodes and results
        '''
        if len(self.transfer_nodes) > 0:
            reply = QMessageBox.question(
                self.ui.transfer_node_parameter_group,
                'Herkunfts-/Zielpunkt entfernen',
                'Die Berechnung der Herkunfts-/Zielpunkte setzt alle '
                'vorhandenen Punkte und Berechnungen zurück.\n'
                'Wollen Sie die Berechnung fortsetzen?', QMessageBox.Yes,
                QMessageBox.No)
            if reply == QMessageBox.No:
                return
        self.transfer_nodes.table.truncate()
        self.links.table.truncate()
        self.traffic_load.table.truncate()
        distance = self.ui.distance_input.value()
        job = TransferNodeCalculation(self.project, distance=distance)

        def on_success(res):
            self.draw_nodes()
            self.draw_itineraries(zoom_to=True)

        def on_close():
            self.fill_node_combo()
            self.setup_weights()
            self.canvas.refreshAllLayers()

        dialog = ProgressDialog(job,
                                parent=self.ui,
                                on_success=on_success,
                                on_close=on_close)
        dialog.show()
Exemplo n.º 5
0
    def calculate(self):
        '''
        calculate the impact of the changes to status quo and show the results
        as layers
        '''
        job = Projektwirkung(self.project, recalculate=False)
        success, msg = job.validate_inputs()
        if not success:
            QMessageBox.warning(self.ui, 'Fehler', msg)
            return
        self.remove_results()

        def on_success(r):
            self.show_results()
            if not self.settings.show_result_layer_info:
                return
            msg_box = QMessageBox(self.ui)
            msg_box.setText(
                'Die Ergebnislayer wurden dem QGIS-Layerbaum '
                'in der Gruppe "Projektwirkung" hinzugefügt. Nur der'
                ' oberste Ergebnislayer ist aktiviert.\n\n'
                'Um die anderen Ergebnisse anzuzeigen, '
                'aktivieren Sie sie bitte manuell im Layerbaum.\n')
            check = QCheckBox('nicht wieder anzeigen')
            msg_box.setCheckBox(check)
            msg_box.exec()
            if check.isChecked():
                self.settings.show_result_layer_info = False

        dialog = ProgressDialog(job, parent=self.ui, on_success=on_success)
        dialog.show()
Exemplo n.º 6
0
    def calculate(self):
        '''
        calculate migration of jobs
        '''
        if not self.ui.recalculate_jobs_check.isChecked():
            self.add_layer(toggle_if_exists=True)
            return
        sum_ap = sum(x or 0 for x in self.areas.values('ap_gesamt'))
        if sum_ap == 0:
            # ToDo: actually there are just no jobs
            # (e.g. when manually set to zero)
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Es wurden keine definierten Teilflächen mit '
                'der Nutzungsart "Gewerbe" gefunden.')
            return

        job = SvBMigrationCalculation(self.project)

        def on_close():
            self.changed.emit()
            if not self.dialog.success:
                self.wanderung.table.truncate()
                self.ui.recalculate_inhabitants_check.setVisible(False)
                self.ui.recalculate_inhabitants_check.setChecked(True)
                return
            self.ui.recalculate_jobs_check.setVisible(True)
            self.ui.recalculate_jobs_check.setChecked(False)
            self.add_layer()
            self.setup_params()

        self.dialog = ProgressDialog(job, parent=self.ui, on_close=on_close)
        self.dialog.show()
Exemplo n.º 7
0
    def calculate(self):
        '''
        calculate the property tax
        '''
        job = GrundsteuerCalculation(self.project)

        def on_success(r):
            self.add_layer()

        self.changed.emit()
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()
    def calculate_gesamtkosten(self):
        '''
        calculate total costs of infrastructure and show diagram of results
        '''
        job = GesamtkostenErmitteln(self.project)

        def on_close():
            if not self.dialog.success:
                return
            diagram = GesamtkostenDiagramm(project=self.project,
                                           years=GesamtkostenErmitteln.years)
            diagram.draw()

        self.dialog = ProgressDialog(job, parent=self.ui, on_close=on_close,
                                     auto_close=True)
        self.dialog.show()
    def calculate_kostentraeger(self):
        '''
        calculations of cost shares
        '''
        job = KostentraegerAuswerten(self.project)

        def on_close():
            if not self.dialog.success:
                return
            # the years originate from gesamtkosten calculation
            diagram = KostentraegerDiagramm(project=self.project,
                                           years=GesamtkostenErmitteln.years)
            diagram.draw()

        self.dialog = ProgressDialog(job, parent=self.ui,  on_close=on_close,
                                     auto_close=True)
        self.dialog.show()
Exemplo n.º 10
0
    def read_osm(self):
        '''
        query geoserver for markets in the study area and add them to the
        status quo markets
        '''
        buffer = self.ui.osm_buffer_input.value() \
            if self.ui.osm_buffer_check.isChecked() else 0
        job = ReadOSMWorker(self.project,
                            epsg=self.settings.EPSG,
                            buffer=buffer,
                            truncate=False)

        def on_success(r):
            self.nullfall_edit.fill_combo()
            self.nullfall_edit.add_layer(zoom_to=True)
            self.changed_edit.fill_combo()
            self.remove_results()

        dialog = ProgressDialog(job, parent=self.ui, on_success=on_success)
        dialog.show()
Exemplo n.º 11
0
    def calculate(self):
        '''
        calculate the business tax
        '''
        if len(BeschaeftigtenWanderung.features()) == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Wanderungssalden '
                '(Beschäftigte) durch.')
            return
        job = GewerbesteuerCalculation(self.project)

        def on_success(r):
            self.add_layer()

        self.changed.emit()
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()
Exemplo n.º 12
0
    def calc_fam_ausgleich(self):
        '''
        calculate the family compensation based on the income tax
        '''
        if sum([abs(gem.einkommensteuer) for gem in self.gemeinden]) == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Einkommensteuer '
                'durch.')
            return
        job = FamAusgleichCalculation(self.project)

        def on_success(r):
            self.add_fla_layer()

        self.reset_results(fields=['summe_einnahmen'])
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()
Exemplo n.º 13
0
    def calc_einkommensteuer(self):
        '''
        calculate the income tax based on the inhabitant migration
        '''
        if len(self.migration_ew.wanderung) == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Wanderungssalden '
                '(Einwohner) durch.')
            return
        job = EinkommensteuerCalculation(self.project)

        def on_success(r):
            self.add_est_layer()

        self.reset_results(
            fields=['fam_leistungs_ausgleich', 'summe_einnahmen'])
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()
Exemplo n.º 14
0
    def save(self):
        '''
        write the current parameter values to the database
        '''
        we_sum = 0
        for bt in self.gebaeudetypen_base:
            feature = self.wohneinheiten.get(id_gebaeudetyp=bt.id,
                                             id_teilflaeche=self.area.id)
            if not feature:
                feature = self.wohneinheiten.add(
                    id_gebaeudetyp=bt.id, id_teilflaeche=self.area.id)
            we = getattr(self.params, bt.param_we).value
            feature.we = we
            we_sum += we
            ew_je_we = getattr(self.params, bt.param_ew_je_we).value
            feature.ew_je_we = ew_je_we
            anteil_u18 = getattr(self.params, bt.param_anteil_u18).value
            feature.anteil_u18 = anteil_u18
            cor_factor = ew_je_we / bt.Ew_pro_WE_Referenz
            feature.korrekturfaktor = cor_factor
            feature.name_gebaeudetyp = bt.NameGebaeudetyp
            feature.save()

        self.area.beginn_nutzung = self.params.beginn_nutzung.value
        self.area.aufsiedlungsdauer = self.params.aufsiedlungsdauer.value
        self.area.we_gesamt = we_sum

        Traffic.reset()
        MunicipalTaxRevenue.reset_wohnen()

        self.area.save()

        job = WohnenDevelopment(self.basedata, self.area)

        dialog = ProgressDialog(
            job, auto_close=True,
            parent=self.layout.parentWidget())
        dialog.show()
Exemplo n.º 15
0
    def calculate_traffic(self):
        '''
        calculate the traffic load
        '''
        max_dist = getattr(self.settings, 'MAX_AREA_DISTANCE', None)
        points = [c.geom.asPoint() for c in self.connectors]
        xs = [p.x() for p in points]
        ys = [p.y() for p in points]
        if max_dist is not None:
            distances = []
            for i in range(len(points)):
                for j in range(i):
                    dist = np.linalg.norm(
                        np.subtract((xs[i], ys[i]), (xs[j], ys[j])))
                    distances.append(dist)
            if distances and max(distances) > 2 * max_dist:
                QMessageBox.warning(
                    self.ui, 'Hinweis',
                    'Der Abstand zwischen den Anbindungspunkten ist zu groß. '
                    'Er darf für die Schätzung der Verkehrsbelastung jeweils '
                    f'nicht größer als {2 * max_dist} m sein!')
                return

        if len(self.traffic_load) == 0:
            recalculate = len(self.links) == 0
            job = Routing(self.project, recalculate=recalculate)

            def on_success(res):
                if self.itinerary_output:
                    self.itinerary_output.remove()
                self.draw_nodes()
                self.draw_traffic(zoom_to=True)
                self.setup_weights()

            dialog = ProgressDialog(job, parent=self.ui, on_success=on_success)
            dialog.show()
        else:
            self.draw_traffic(zoom_to=True, toggle_if_exists=True)
Exemplo n.º 16
0
    def read_template(self):
        '''
        let the user select a template and load its entries to the status quo
        markets
        '''
        filters = [
            f'*{ext[0]}' for ext in MarketTemplate.template_types.values()
        ]
        path, f = QFileDialog.getOpenFileName(
            self.ui, 'Templatedatei öffnen', None,
            f'Templatedatei ({" ".join(filters)})')
        if path:

            def on_success(r):
                self.nullfall_edit.fill_combo()
                self.nullfall_edit.add_layer(zoom_to=True)
                self.changed_edit.fill_combo()
                self.remove_results()

            job = MarketTemplateImportWorker(path,
                                             self.project,
                                             epsg=self.settings.EPSG)
            dialog = ProgressDialog(job, parent=self.ui, on_success=on_success)
            dialog.show()
Exemplo n.º 17
0
    def create_project(self):
        '''
        Open a dialog for setting up a new project and create the project
        based on this setup. Automatically set the new project as active project
        if successfully created
        '''
        status, msg = self.project_manager.check_basedata()
        if status == 0:
            QMessageBox.warning(self.ui, 'Hinweis', msg)
            self.ui.project_combo.setCurrentIndex(0)
            return
        dialog = NewProjectDialog()
        ok, name, layer = dialog.show()

        if ok:
            job = ProjectInitialization(name,
                                        layer,
                                        self.project_manager.settings.EPSG,
                                        parent=self.ui)
            self.project_manager.load_basedata()

            def on_success(project):
                self.project_manager.active_project = project
                self.ui.project_combo.addItem(project.name, project)
                self.ui.project_combo.setCurrentIndex(
                    self.ui.project_combo.count() - 1)

            def on_close():
                if not dialog.success:
                    # ToDo: after stopping the creation of a project the
                    # connection often can't be closed anymore
                    try:
                        self.project_manager.remove_project(job.project)
                    except PermissionError:
                        pass

            dialog = ProgressDialog(job,
                                    parent=self.ui,
                                    on_success=on_success,
                                    on_close=on_close)
            dialog.show()
Exemplo n.º 18
0
class EinwohnerMigration(Migration):
    '''
    migration of inhabitants
    '''
    def __init__(self, project, ui, layer_group, canvas):
        super().__init__(project, ui, layer_group, canvas)
        self.ui.migration_inhabitants_button.clicked.connect(self.calculate)

    def load_content(self):
        super().load_content()
        self.wanderung = EinwohnerWanderung.features(create=True)

        self.ui.einwohner_parameter_group.setVisible(False)
        if len(self.wanderung) == 0:
            self.ui.recalculate_inhabitants_check.setChecked(True)
            self.ui.recalculate_inhabitants_check.setVisible(False)
            self.ui.einwohner_parameter_group.setVisible(False)
        else:
            self.setup_params()

    def calculate(self):
        '''
        calculate the migration
        '''
        if not self.ui.recalculate_inhabitants_check.isChecked():
            self.add_layer(toggle_if_exists=True)
            return
        sum_ew = sum(x or 0 for x in self.areas.values('ew'))
        if sum_ew == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Es wurden keine definierten Teilflächen mit '
                'der Nutzungsart "Wohnen" gefunden.')
            return

        job = EwMigrationCalculation(self.project)

        def on_close():
            self.changed.emit()
            if not self.dialog.success:
                self.wanderung.table.truncate()
                self.ui.recalculate_inhabitants_check.setVisible(False)
                self.ui.recalculate_inhabitants_check.setChecked(True)
                return
            self.ui.recalculate_inhabitants_check.setVisible(True)
            self.ui.recalculate_inhabitants_check.setChecked(False)
            self.add_layer()
            self.setup_params()

        self.dialog = ProgressDialog(job, parent=self.ui, on_close=on_close)
        self.dialog.show()

    def setup_params(self):
        '''
        set up migration settings for each muncipality in study area
        '''
        if self.params:
            self.params.close()
        self.ui.einwohner_parameter_group.setVisible(True)
        layout = self.ui.einwohner_parameter_group.layout()
        clear_layout(layout)
        self.params = Params(layout,
                             help_file='einnahmen_einwohner_wanderung.txt')

        self.df_wanderung = self.wanderung.to_pandas()

        randsummen = self.project.basedata.get_table('Wanderung_Randsummen',
                                                     'Einnahmen').features()
        factor_inner = randsummen.get(IDWanderungstyp=1).Anteil_Wohnen
        factor_outer = randsummen.get(IDWanderungstyp=2).Anteil_Wohnen
        project_ags = self.project_frame.ags
        project_gem = self.gemeinden.get(AGS=project_ags)
        wanderung = self.wanderung.get(AGS=project_ags)
        sum_ew = sum(x or 0 for x in self.areas.values('ew'))

        def update_salden(ags_changed):
            param = self.params[ags_changed]
            fixed = param.is_locked
            saldo = param.input.value
            idx = self.df_wanderung['AGS'] == ags_changed
            if fixed:
                fixed_fortzug = self.df_wanderung[np.invert(idx)
                                                  & self.df_wanderung['fixed']
                                                  == True]['fortzug'].sum()
                # the rest of "fortzüge" that can be applied to this row
                min_value = fixed_fortzug - (sum_ew * factor_inner)
                saldo = max(saldo, min_value)
                zuzug = self.df_wanderung[idx]['zuzug'].values[0]
                self.df_wanderung.loc[idx, 'fortzug'] = zuzug - saldo
            self.df_wanderung.loc[idx, 'fixed'] = fixed
            self.df_wanderung.loc[idx, 'saldo'] = saldo
            self.df_wanderung = MigrationCalculation.calculate_saldi(
                self.df_wanderung, factor_inner, project_ags)
            for gemeinde_ags in self.df_wanderung['AGS'].values:
                param = self.params[gemeinde_ags]
                row = self.df_wanderung[self.df_wanderung['AGS'] ==
                                        gemeinde_ags]
                param.input.blockSignals(True)
                param.input.value = row['saldo'].values[0]
                param.input.blockSignals(False)

        self.params.add(Title('Standortgemeinde des Projekts', bold=False))

        spinbox = DoubleSpinBox(minimum=0,
                                maximum=1000,
                                step=1,
                                lockable=True,
                                locked=wanderung.fixed,
                                reversed_lock=True)
        project_saldo = Param(wanderung.saldo,
                              spinbox,
                              repr_format='%+.2f',
                              label=f' - {project_gem.GEN}',
                              unit='Ew')
        self.params.add(project_saldo, name=project_ags)
        spinbox.changed.connect(lambda o: update_salden(project_ags))
        spinbox.locked.connect(lambda o: update_salden(project_ags))

        self.params.add(Seperator())
        self.params.add(Title('Region um Standortgemeinde', bold=False))

        for gemeinde in sorted(self.gemeinden, key=lambda x: x.GEN):
            ags = gemeinde.AGS
            if ags == project_ags:
                continue
            wanderung = self.wanderung.get(AGS=ags)
            if not wanderung:
                continue
            spinbox = DoubleSpinBox(minimum=-1000,
                                    maximum=0,
                                    step=1,
                                    lockable=True,
                                    locked=wanderung.fixed,
                                    reversed_lock=True)
            param = Param(wanderung.saldo,
                          spinbox,
                          label=f' - {gemeinde.GEN}',
                          unit='Ew')
            self.params.add(param, name=ags)
            spinbox.changed.connect(lambda o, a=ags: update_salden(a))
            spinbox.locked.connect(lambda o, a=ags: update_salden(a))

        self.params.add(Seperator())

        self.params.add(
            Param(-factor_outer * sum_ew,
                  label='Restliches Bundesgebiet / Ausland',
                  unit='Ew'))

        def save():
            self.wanderung.update_pandas(self.df_wanderung)
            self.changed.emit()
            self.canvas.refreshAllLayers()

        self.params.show(title='Geschätzte Salden (Einwohner) bearbeiten',
                         scrollable=True)
        self.params.changed.connect(save)

    def add_layer(self, toggle_if_exists=False):
        '''
        show layer with migration of inhabitants
        '''
        self.output = ProjectLayer.from_table(self.wanderung.table,
                                              groupname=self.layer_group)
        self.output.draw(label='Wanderungssalden Einwohner',
                         style_file='einnahmen_einwohnerwanderung.qml',
                         uncheck_siblings=True,
                         redraw=not toggle_if_exists,
                         toggle_if_exists=toggle_if_exists)
        if self.output.tree_layer.isVisible():
            self.output.zoom_to()
class Gesamtkosten:
    '''
    edit cost parameters and calculation of costs
    '''
    def __init__(self, ui, project):
        self.ui = ui
        self.project = project
        self.ui.gesamtkosten_button.clicked.connect(self.calculate_gesamtkosten)

        self.netzelemente = self.project.basedata.get_table(
            'Netze_und_Netzelemente', 'Kosten'
        ).features().filter(Typ='Linie')

        for i, netzelement in enumerate(self.netzelemente):
            net_element_id = netzelement.IDNetzelement
            radio = QRadioButton(netzelement.Netzelement)
            self.ui.kostenkennwerte_radio_grid.addWidget(radio, i // 2, i % 2)
            if i == 0:
                self.net_element_id = net_element_id
                radio.setChecked(True)
            radio.toggled.connect(
                lambda b, i=net_element_id: self.setup_net_element(i)
            )

    def load_content(self):
        self.kostenkennwerte = KostenkennwerteLinienelemente.features(
            create=True)
        if len(self.kostenkennwerte) == 0:
            init_kostenkennwerte(self.project)
        self.setup_net_element(self.net_element_id)

    def calculate_gesamtkosten(self):
        '''
        calculate total costs of infrastructure and show diagram of results
        '''
        job = GesamtkostenErmitteln(self.project)

        def on_close():
            if not self.dialog.success:
                return
            diagram = GesamtkostenDiagramm(project=self.project,
                                           years=GesamtkostenErmitteln.years)
            diagram.draw()

        self.dialog = ProgressDialog(job, parent=self.ui, on_close=on_close,
                                     auto_close=True)
        self.dialog.show()

    def setup_net_element(self, net_element_id):
        '''
        set up parameters to edit the costs per element and phase
        '''
        self.net_element_id = net_element_id
        ui_group = self.ui.kostenkennwerte_params_group
        net_element_name = self.netzelemente.get(
            IDNetzelement=net_element_id).Netzelement
        ui_group.setTitle(net_element_name)
        layout = ui_group.layout()
        clear_layout(layout)
        net_element = self.kostenkennwerte.get(IDNetzelement=net_element_id)

        self.params = Params(
            layout, help_file='infrastruktur_kostenkennwerte.txt')

        self.params.euro_EH = Param(
            net_element.Euro_EH, DoubleSpinBox(),
            unit='€', label='Kosten der erstmaligen Herstellung \n'
            'pro laufenden Meter'
        )
        self.params.euro_BU = Param(
            net_element.Cent_BU / 100, DoubleSpinBox(),
            unit='€', label='Jährliche Kosten für Betrieb und Unterhaltung \n'
            'pro laufenden Meter und Jahr'
        )
        self.params.euro_EN = Param(
            net_element.Euro_EN, DoubleSpinBox(),
            unit='€', label='Kosten der Erneuerung \n'
            'pro laufenden Meter und Erneuerungszyklus'
        )
        self.params.lebensdauer = Param(
            net_element.Lebensdauer, SpinBox(minimum=1, maximum=1000),
            label='Lebensdauer: Jahre zwischen den Erneuerungszyklen',
            unit='Jahr(e)'
        )

        self.params.show()
        self.params.changed.connect(lambda: self.save(net_element_id))


    def save(self, net_element_id):
        '''
        write the current values of the parameters to database
        '''
        net_element = self.kostenkennwerte.get(IDNetzelement=net_element_id)
        net_element.Euro_EH = self.params.euro_EH.value
        net_element.Lebensdauer = self.params.lebensdauer.value
        net_element.Cent_BU = self.params.euro_BU.value * 100
        net_element.Euro_EN = self.params.euro_EN.value
        net_element.save()
Exemplo n.º 20
0
class MunicipalTaxRevenue(Domain):
    '''
    domain-widget for analyzing the job and inhabitant migration and the
    resulting tax revenue changes
    '''
    radius = 25000

    ui_label = 'Kommunale Steuereinnahmen'
    ui_file = 'domain_07-KSt.ui'
    ui_icon = "images/iconset_mob/20190619_iconset_mob_domain_tax_1.png"
    layer_group = 'Wirkungsbereich 6 - Kommunale Steuereinnahmen'

    def setupUi(self):
        self.migration_ew = EinwohnerMigration(self.project, self.ui,
                                               self.layer_group, self.canvas)
        self.migration_svb = BeschaeftigtenMigration(self.project, self.ui,
                                                     self.layer_group,
                                                     self.canvas)
        self.grundsteuer = Grundsteuer(self.project, self.ui, self.layer_group)
        self.gewerbesteuer = Gewerbesteuer(self.project, self.ui,
                                           self.layer_group)
        self.areas = Teilflaechen.features()

        manual_path = os.path.join(self.settings.HELP_PATH,
                                   'Anleitung_Kommunale_Steuereinnahmen.pdf')
        self.ui.manual_button.clicked.connect(lambda: open_file(manual_path))
        result_help_path = os.path.join(
            self.settings.HELP_PATH,
            'Hinweise_zur_Ergebnisinterpretation_Kommunale_Einnahmen.pdf')
        self.ui.result_help_button.clicked.connect(
            lambda: open_file(result_help_path))

        self.ui.calc_einkommensteuer_button.clicked.connect(
            self.calc_einkommensteuer)
        self.ui.calc_fla_button.clicked.connect(self.calc_fam_ausgleich)
        self.ui.calc_umsatzsteuer_button.clicked.connect(
            self.calc_umsatzsteuer)
        self.ui.calc_gesamtsumme_button.clicked.connect(self.calc_gesamtsumme)

        self.migration_ew.changed.connect(lambda: self.reset_results(fields=[
            'grundsteuer', 'einkommensteuer', 'fam_leistungs_ausgleich',
            'summe_einnahmen'
        ]))
        self.migration_svb.changed.connect(lambda: self.reset_results(
            fields=['gewerbesteuer', 'umsatzsteuer', 'summe_einnahmen']))
        self.grundsteuer.changed.connect(lambda: self.reset_results(
            fields=['grundsteuer', 'summe_einnahmen']))
        self.gewerbesteuer.changed.connect(lambda: self.reset_results(
            fields=['gewerbesteuer', 'umsatzsteuer', 'summe_einnahmen']))

    def load_content(self):
        super().load_content()
        self.project_frame = Projektrahmendaten.features(
            project=self.project)[0]
        self.gemeinden = Gemeindebilanzen.features(create=True)
        if len(self.gemeinden) == 0:
            self.init_gemeinden()

        self.migration_ew.load_content()
        self.migration_svb.load_content()
        self.grundsteuer.load_content()
        self.gewerbesteuer.load_content()

    def init_gemeinden(self):
        '''
        get the muncipalities around the project areas and store them
        '''
        gemeinden = self.project.basedata.get_table('bkg_gemeinden',
                                                    'Basisdaten_deutschland')
        buffer_geom = self.project_frame.geom.buffer(self.radius, 5)
        gemeinden.spatial_filter(buffer_geom.asWkt())
        # project table has some of the fields of the basedata table
        # (same names)
        common_fields = set([f.name for f in gemeinden.fields()]).intersection(
            [f.name for f in self.gemeinden.fields()])
        for gemeinde in gemeinden:
            attrs = {}
            for field in common_fields:
                attrs[field] = gemeinde[field]
            attrs['geom'] = gemeinde['geom']
            self.gemeinden.add(**attrs)

    def calc_einkommensteuer(self):
        '''
        calculate the income tax based on the inhabitant migration
        '''
        if len(self.migration_ew.wanderung) == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Wanderungssalden '
                '(Einwohner) durch.')
            return
        job = EinkommensteuerCalculation(self.project)

        def on_success(r):
            self.add_est_layer()

        self.reset_results(
            fields=['fam_leistungs_ausgleich', 'summe_einnahmen'])
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()

    def calc_fam_ausgleich(self):
        '''
        calculate the family compensation based on the income tax
        '''
        if sum([abs(gem.einkommensteuer) for gem in self.gemeinden]) == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Einkommensteuer '
                'durch.')
            return
        job = FamAusgleichCalculation(self.project)

        def on_success(r):
            self.add_fla_layer()

        self.reset_results(fields=['summe_einnahmen'])
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()

    def calc_umsatzsteuer(self):
        '''
        calculate the value added tax based on the business tax
        '''
        if sum([abs(gem.gewerbesteuer) for gem in self.gemeinden]) == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Gewerbesteuer '
                'durch.')
            return
        ust_base = self.basedata.get_table('USt_Kennwerte',
                                           'Einnahmen').features()[0]
        factor_gst = ust_base.GemAnt_USt_EUR_pro_EUR_GewSt
        factor_svb = ust_base.GemANt_USt_EUR_pro_SvB
        for gem in self.gemeinden:
            wanderung = self.migration_svb.wanderung.get(AGS=gem.AGS)
            saldo = wanderung.saldo if wanderung else 0
            ust = factor_gst * gem.gewerbesteuer + factor_svb * saldo
            rnd = 1000 if ust >= 500 else 100
            ust = round(ust / rnd) * rnd
            gem.umsatzsteuer = ust
            gem.save()
        self.reset_results(fields=['summe_einnahmen'])
        self.add_ust_layer()

    def calc_gesamtsumme(self):
        '''
        calculate the total change of tax revenue
        '''
        tou = self.areas.values('nutzungsart')
        if (Nutzungsart.WOHNEN.value in tou and sum(
            [abs(gem.fam_leistungs_ausgleich)
             for gem in self.gemeinden]) == 0):
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung des '
                'Familienleistungsausgleichs durch.')
            return
        if ((Nutzungsart.GEWERBE.value in tou
             or Nutzungsart.EINZELHANDEL.value in tou)
                and sum([abs(gem.umsatzsteuer)
                         for gem in self.gemeinden]) == 0):
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Umsatzsteuer '
                'durch.')
            return
        for gem in self.gemeinden:
            gem.summe_einnahmen = (gem.grundsteuer + gem.einkommensteuer +
                                   gem.gewerbesteuer + gem.umsatzsteuer +
                                   gem.fam_leistungs_ausgleich)
            gem.save()
        self.add_gesamt_layer()

    def add_est_layer(self):
        '''
        show income tax layer
        '''
        self.output = ProjectLayer.from_table(self.gemeinden.table,
                                              groupname=self.layer_group)
        self.output.draw(label='Einkommensteuer',
                         style_file='einnahmen_einkommensteuer.qml',
                         filter="einkommensteuer != 'NULL'",
                         uncheck_siblings=True,
                         redraw=False)
        self.output.zoom_to()

    def add_fla_layer(self):
        '''
        show family compensation layer
        '''
        self.output = ProjectLayer.from_table(self.gemeinden.table,
                                              groupname=self.layer_group)
        self.output.draw(label='Familienleistungsausgleich',
                         style_file='einnahmen_fam_leistungs_ausgleich.qml',
                         filter="fam_leistungs_ausgleich != 'NULL'",
                         uncheck_siblings=True,
                         redraw=False)
        self.output.zoom_to()

    def add_ust_layer(self):
        '''
        show value added tax layer
        '''
        self.output = ProjectLayer.from_table(self.gemeinden.table,
                                              groupname=self.layer_group)
        self.output.draw(label='Umsatzsteuer',
                         style_file='einnahmen_umsatzsteuer.qml',
                         filter="umsatzsteuer != 'NULL'",
                         uncheck_siblings=True,
                         redraw=False)
        self.output.zoom_to()

    def add_gesamt_layer(self):
        '''
        show layer with total changes in tax revenues
        '''
        self.output = ProjectLayer.from_table(self.gemeinden.table,
                                              groupname=self.layer_group)
        self.output.draw(label='Gesamtsumme Einnahmen',
                         style_file='einnahmen_summe_einnahmen.qml',
                         filter="summe_einnahmen != 'NULL'",
                         uncheck_siblings=True,
                         redraw=False)
        self.output.zoom_to()

    @classmethod
    def reset_results(cls,
                      fields=[
                          'grundsteuer', 'einkommensteuer', 'gewerbesteuer',
                          'umsatzsteuer', 'fam_leistungs_ausgleich',
                          'summe_einnahmen'
                      ]):
        '''
        remove the results and layers
        '''
        bilanzen = Gemeindebilanzen.features(create=True)
        df_bilanzen = bilanzen.to_pandas()
        for field in fields:
            df_bilanzen[field] = None
        bilanzen.update_pandas(df_bilanzen)
        canvas = utils.iface.mapCanvas()
        canvas.refreshAllLayers()

    @classmethod
    def reset_gewerbe_einzelhandel(cls):
        '''
        remove the results based on changes of business and retail trade
        '''
        BeschaeftigtenWanderung.get_table(create=True).truncate()
        cls.reset_results(fields=[
            'grundsteuer', 'gewerbesteuer', 'umsatzsteuer', 'summe_einnahmen'
        ])

    @classmethod
    def reset_wohnen(cls):
        '''
        remove the results based on residential changes
        '''
        EinwohnerWanderung.get_table(create=True).truncate()
        cls.reset_results(fields=[
            'grundsteuer', 'fam_leistungs_ausgleich', 'einkommensteuer',
            'summe_einnahmen'
        ])

    def close(self):
        self.migration_ew.close()
        self.grundsteuer.close()
        self.migration_svb.close()
        self.gewerbesteuer.close()
        super().close()
class Kostentraeger:
    '''
    parameters and calculations of shares of infrastructural costs between
    different payers
    '''

    def __init__(self, ui, project):
        self.ui = ui
        self.project = project
        self.ui.kostentraeger_button.clicked.connect(
            self.calculate_kostentraeger)

        self.default_kostenaufteilung = self.project.basedata.get_table(
            'Kostenaufteilung_Startwerte', 'Kosten')
        self.kostenphasen = self.project.basedata.get_table(
            'Kostenphasen', 'Kosten').features()
        self.aufteilungsregeln = self.project.basedata.get_table(
            'Aufteilungsregeln', 'Kosten').features()
        self.applyable_aufteilungsregeln = self.project.basedata.get_table(
            'Aufteilungsregeln_zu_Netzen_und_Phasen', 'Kosten').features()
        self.netzelemente = self.project.basedata.get_table(
            'Netze_und_Netzelemente', 'Kosten', fields=['IDNetz', 'Netz']
        ).features()

        df_netzelemente = self.netzelemente.to_pandas()
        del df_netzelemente['fid']
        df_netzelemente.drop_duplicates(inplace=True)

        for i, (index, row) in enumerate(df_netzelemente.iterrows()):
            net_id = row['IDNetz']
            net_name = row['Netz']
            radio = QRadioButton(net_name)
            self.ui.kostenaufteilung_radio_grid.addWidget(radio, i // 2, i % 2)
            if i == 0:
                self.net_id = net_id
                radio.setChecked(True)
            radio.toggled.connect(
                lambda b, i=net_id: self.setup_kostenaufteilung(i))

    def load_content(self):
        self.kostenaufteilung = Kostenaufteilung.features(
            create=True, project=self.project)

        # initialize empty project 'kostenaufteilungen' with the default ones
        if len(self.kostenaufteilung) == 0:
            for default in self.default_kostenaufteilung.features():
                rule = self.aufteilungsregeln.get(
                    IDAufteilungsregel=default.IDKostenregel)
                self.kostenaufteilung.add(
                    Anteil_GSB=rule.Anteil_GSB,
                    Anteil_GEM=rule.Anteil_GEM,
                    Anteil_ALL=rule.Anteil_ALL,
                    IDNetz=default.IDNetz,
                    IDKostenphase=default.IDKostenphase
                )

        self.setup_kostenaufteilung(self.net_id)

    def calculate_kostentraeger(self):
        '''
        calculations of cost shares
        '''
        job = KostentraegerAuswerten(self.project)

        def on_close():
            if not self.dialog.success:
                return
            # the years originate from gesamtkosten calculation
            diagram = KostentraegerDiagramm(project=self.project,
                                           years=GesamtkostenErmitteln.years)
            diagram.draw()

        self.dialog = ProgressDialog(job, parent=self.ui,  on_close=on_close,
                                     auto_close=True)
        self.dialog.show()

    def setup_kostenaufteilung(self, net_id):
        '''
        set up parameters to edit shares for a specific type of infrastructure
        '''
        self.net_id = net_id
        ui_group = self.ui.kostenaufteilung_params_group
        net_name = self.netzelemente.filter(IDNetz=net_id)[0].Netz
        ui_group.setTitle(net_name)
        layout = ui_group.layout()
        clear_layout(layout)

        self.params = Params(
            layout, help_file='infrastruktur_kostenaufteilung.txt')
        field_names = ['Anteil_GSB', 'Anteil_GEM', 'Anteil_ALL']
        labels = ['Kostenanteil der Grunstücksbesitzer/innen',
                  'Kostenanteil der Gemeinde',
                  'Netznutzer/innen und Tarifkundschaft']

        def preset_changed(c, p):
            preset = c.get_data()
            if not preset:
                return
            for field_name in field_names:
                param = self.params.get(f'{p.Kostenphase}_{field_name}')
                param.input.value = preset[field_name]

        for i, phase in enumerate(self.kostenphasen):
            dependency = SumDependency(100)
            self.params.add(Title(phase.Kostenphase))
            feature = self.kostenaufteilung.get(
                IDKostenphase=phase.IDKostenphase, IDNetz=net_id)

            preset_combo, options = self.create_presets(
                net_id, phase.IDKostenphase)
            param = Param(0, preset_combo, label='Vorschlagswerte')
            param.hide_in_overview = True
            self.params.add(param, name=f'{phase.Kostenphase}_presets')

            for j, field_name in enumerate(field_names):
                label = labels[j]
                slider = Slider(maximum=100, lockable=True)
                param = Param(feature[field_name], slider,
                              label=label, unit='%')
                self.params.add(
                    param, name=f'{phase.Kostenphase}_{field_name}')
                dependency.add(param)
                slider.changed.connect(
                    lambda b,
                    c=preset_combo, o=options: c.set_value(o[0]))

            if i != len(self.kostenphasen) - 1:
                self.params.add(Seperator(margin=0))

            preset_combo.changed.connect(
                lambda b, c=preset_combo, p=phase: preset_changed(c, p))

        self.params.show(title='Kostenaufteilung festlegen')
        self.params.changed.connect(lambda: self.save(net_id))

    def create_presets(self, net_id: int, phase_id: int) -> tuple:
        '''
        create a combobox with presets for shares for a specific phase and type
        of infrastructure element
        '''
        applyable_rules = self.applyable_aufteilungsregeln.filter(
            IDNetz=net_id, IDPhase=phase_id)
        rules = []
        for applyable_rule in applyable_rules:
            rule_id = applyable_rule.IDAufteilungsregel
            rule = self.aufteilungsregeln.get(IDAufteilungsregel=rule_id)
            rules.append(rule)

        options = (['Aufteilungsregel wählen'] +
                   [rule.Aufteilungsregel for rule in rules])
        preset_combo = ComboBox(options, [None] + rules)
        preset_combo.input.model().item(0).setEnabled(False)
        return preset_combo, options

    def save(self, net_id):
        '''
        write the current settings of paramaters for a specific type of
        infrastructure element
        '''
        for phase in self.kostenphasen:
            feature = self.kostenaufteilung.get(
                IDKostenphase=phase.IDKostenphase, IDNetz=net_id)
            for field_name in ['Anteil_GSB', 'Anteil_GEM', 'Anteil_ALL']:
                param = self.params[f'{phase.Kostenphase}_{field_name}']
                feature[field_name] = param.value
            feature.save()
Exemplo n.º 22
0
class Gewerbesteuer(QObject):
    '''
    parameters and calculation of business tax
    '''
    changed = pyqtSignal()

    def __init__(self, project, ui, layer_group):
        super().__init__()
        self.layer_group = layer_group
        self.project = project
        self.ui = ui
        self.ui.calc_gewerbesteuer_button.clicked.connect(self.calculate)
        self.params = None

    def load_content(self):
        self.gemeinden = Gemeindebilanzen.features(project=self.project)
        self.setup_params()

    def setup_params(self):
        if self.params:
            self.params.close()
        layout = self.ui.gewerbesteuer_hebesatz_param_group.layout()
        clear_layout(layout)
        self.params = Params(layout,
                             help_file='einnahmen_gewerbesteuer_hebesätze.txt')

        self.params.add(Title('Hebesätze', bold=False))

        for gemeinde in sorted(self.gemeinden, key=lambda x: x.GEN):
            spinbox = SpinBox(minimum=0, maximum=999, step=1)
            param = Param(gemeinde.Hebesatz_GewSt,
                          spinbox,
                          label=f' - {gemeinde.GEN}',
                          unit='v.H.')
            self.params.add(param, name=gemeinde.AGS)

        def save():
            self.changed.emit()
            for gemeinde in self.gemeinden:
                param = self.params[gemeinde.AGS]
                gemeinde.Hebesatz_GewSt = param.value
                gemeinde.save()

        self.params.show(title='Hebesätze Gewerbesteuer bearbeiten',
                         scrollable=True)
        self.params.changed.connect(save)

    def calculate(self):
        '''
        calculate the business tax
        '''
        if len(BeschaeftigtenWanderung.features()) == 0:
            QMessageBox.warning(
                self.ui, 'Fehler',
                'Bitte führen Sie zunächst die Schätzung der Wanderungssalden '
                '(Beschäftigte) durch.')
            return
        job = GewerbesteuerCalculation(self.project)

        def on_success(r):
            self.add_layer()

        self.changed.emit()
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()

    def add_layer(self):
        '''
        show business tax layer
        '''
        self.output = ProjectLayer.from_table(self.gemeinden.table,
                                              groupname=self.layer_group)
        self.output.draw(label='Gewerbesteuer',
                         style_file='einnahmen_gewerbesteuer.qml',
                         filter="gewerbesteuer != 'NULL'",
                         uncheck_siblings=True,
                         redraw=False)
        self.output.zoom_to()

    def close(self):
        if self.params:
            self.params.close()
class InfrastructuralCosts(Domain):
    '''
    domain-widget for the analysis of required infrastructure and its cost
    '''

    ui_label = 'Infrastrukturfolgekosten'
    ui_file = 'domain_06-IFK.ui'
    ui_icon = ('images/iconset_mob/'
               '20190619_iconset_mob_domain_infrstucturalcosts_4.png')
    layer_group = 'Wirkungsbereich 5 - Infrastrukturfolgekosten'

    def setupUi(self):
        self.drawing = InfrastructureDrawing(self.ui, project=self.project,
                                             canvas=self.canvas,
                                             layer_group=self.layer_group)
        self.kostenaufteilung = Kostentraeger(self.ui, project=self.project)
        self.gesamtkosten = Gesamtkosten(self.ui, project=self.project)
        self.ui.kostenvergleich_button.clicked.connect(self.kostenvergleich)

        pdf_path = os.path.join(
            self.settings.HELP_PATH, 'Anleitung_Infrastrukturfolgekosten.pdf')
        self.ui.manual_button.clicked.connect(lambda: open_file(pdf_path))

        # quite dumb, but expanding a groupbox sets all children to visible
        # but we don't want to see the collapsed widgets
        def hide_widgets():
            self.ui.kostenaufteilung_button.setChecked(False)
            self.ui.kostenkennwerte_button.setChecked(False)
            self.ui.kostenaufteilung_widget.setVisible(False)
            self.ui.kostenkennwerte_widget.setVisible(False)
        self.ui.evaluation_groupbox.collapsedStateChanged.connect(
            hide_widgets)
        hide_widgets()

    def load_content(self):
        super().load_content()
        self.areas = Teilflaechen.features()
        self.drawing.load_content()
        self.kostenaufteilung.load_content()
        self.gesamtkosten.load_content()

    def kostenvergleich(self):
        '''
        calculate the total costs and show a comparison to mean values as a bar
        chart.
        only executable if all areas have either housing or commerce as type of
        use
        '''
        types_of_use = [area.nutzungsart for area in self.areas
                        if area.nutzungsart != Nutzungsart.UNDEFINIERT.value]
        if ((Nutzungsart.WOHNEN.value not in types_of_use and
            Nutzungsart.GEWERBE.value not in types_of_use) or
            len(np.unique(types_of_use)) != 1):
            QMessageBox.warning(
                self.ui, 'Hinweis', 'Die Funktion steht nur für Projekte zur '
                'Verfügung, bei denen alle Teilflächen '
                'ausschließlich die Nutzung Wohnen bzw. Gewerbe haben.'
            )
            return

        job = GesamtkostenErmitteln(self.project)

        def on_close():
            if not self.dialog.success:
                return
            if types_of_use[0] == Nutzungsart.WOHNEN.value:
                diagram = VergleichWEDiagramm(project=self.project)
            else:
                diagram = VergleichAPDiagramm(project=self.project)
            diagram.draw()

        self.dialog = ProgressDialog(job, parent=self.ui, on_close=on_close,
                                     auto_close=True)
        self.dialog.show()


    def close(self):
        '''
        close all parameters and drawing tools
        '''
        if hasattr(self.kostenaufteilung, 'params'):
            self.kostenaufteilung.params.close()
        if hasattr(self.gesamtkosten, 'params'):
            self.gesamtkosten.params.close()
        self.drawing.close()
        super().close()
Exemplo n.º 24
0
class Grundsteuer(QObject):
    '''
    parameters and calculation of property tax
    '''
    changed = pyqtSignal()

    def __init__(self, project, ui, layer_group):
        super().__init__()
        self.project = project
        self.ui = ui
        self.layer_group = layer_group

        self.ui.calc_grundsteuer_button.clicked.connect(self.calculate)

        self.hebesatz_params = None
        self.rohmiete_params = None
        self.sachwert_params = None
        self.bauvolumen_params = None

    def load_content(self):
        self.project_frame = Projektrahmendaten.features(
            project=self.project)[0]
        self.gemeinden = Gemeindebilanzen.features(project=self.project)
        self.grst_settings = GrundsteuerSettings.features(create=True)
        if len(self.grst_settings) == 0:
            self.init_grst_base_settings()
        self.grst_settings = self.grst_settings[0]
        self.areas = Teilflaechen.features(project=self.project)
        self.ew_wanderung = EinwohnerWanderung.features()
        self.svb_wanderung = BeschaeftigtenWanderung.features()

        self.setup_hebesatz()
        self.setup_rohmiete()
        self.setup_sachwert()
        self.setup_bauvolumen()

    def init_grst_base_settings(self):
        '''
        initialize the parameters of the base settings
        '''
        gemeinden = self.project.basedata.get_table(
            'bkg_gemeinden', 'Basisdaten_deutschland').features()
        gem = gemeinden.get(AGS=self.project_frame.ags)
        is_new_bundesland = int(self.project_frame.ags) >= 11000000
        attrs = {
            'Hebesatz_GrStB': gem.Hebesatz_GrStB,
            'is_new_bundesland': is_new_bundesland
        }

        startwerte = self.project.basedata.get_table(
            'GrSt_Startwerte_Rohmieten_Bodenwert', 'Einnahmen').features()
        gem_typ_startwerte = startwerte.get(Gemeindetyp=gem.Gemeindetyp)

        common_fields = set([f.name
                             for f in startwerte.fields()]).intersection(
                                 [f.name for f in self.grst_settings.fields()])

        for field in common_fields:
            attrs[field] = gem_typ_startwerte[field]
        self.grst_settings.add(**attrs)

    def setup_hebesatz(self):
        '''
        assessment rate parameters
        '''
        if self.hebesatz_params:
            self.hebesatz_params.close()
        layout = self.ui.grundsteuer_hebesatz_param_group.layout()
        clear_layout(layout)
        self.hebesatz_params = Params(
            layout, help_file='einnahmen_grundsteuer_hebesatz.txt')

        self.hebesatz_params.hebesatz = Param(
            self.grst_settings.Hebesatz_GrStB,
            SpinBox(maximum=999, step=10),
            label='Hebesatz GrSt B Projektgemeinde',
            unit='v.H.')

        def save():
            self.changed.emit()
            self.grst_settings.Hebesatz_GrStB = \
                self.hebesatz_params.hebesatz.value
            self.grst_settings.save()

        self.hebesatz_params.show(title='Hebesatz bearbeiten')
        self.hebesatz_params.changed.connect(save)

    def setup_rohmiete(self):
        '''
        gross rent parameters
        '''
        tou = self.areas.values('nutzungsart')
        if self.grst_settings.is_new_bundesland \
           or not Nutzungsart.WOHNEN.value in tou:
            self.ui.grundsteuer_rohmiete_param_group.setVisible(False)
            return
        self.ui.grundsteuer_rohmiete_param_group.setVisible(True)
        if self.rohmiete_params:
            self.rohmiete_params.close()
        layout = self.ui.grundsteuer_rohmiete_param_group.layout()
        clear_layout(layout)
        self.rohmiete_params = Params(
            layout, help_file='einnahmen_grundsteuer_rohmieten.txt')

        self.rohmiete_params.add(
            Title('Rohmiete 1964 in Euro pro Monat', bold=False))

        self.rohmiete_params.efh = Param(self.grst_settings.EFH_Rohmiete / 100,
                                         DoubleSpinBox(minimum=0.3,
                                                       maximum=5,
                                                       step=0.05),
                                         label=f' - Einfamilienhaus',
                                         unit='€/m²')
        self.rohmiete_params.dhh = Param(self.grst_settings.DHH_Rohmiete / 100,
                                         DoubleSpinBox(minimum=0.3,
                                                       maximum=5,
                                                       step=0.05),
                                         label=f' - Doppelhaus',
                                         unit='€/m²')
        self.rohmiete_params.rhw = Param(self.grst_settings.RHW_Rohmiete / 100,
                                         DoubleSpinBox(minimum=0.3,
                                                       maximum=5,
                                                       step=0.05),
                                         label=f' - Reihenhaus',
                                         unit='€/m²')
        self.rohmiete_params.mfh = Param(self.grst_settings.MFH_Rohmiete / 100,
                                         DoubleSpinBox(minimum=0.3,
                                                       maximum=5,
                                                       step=0.05),
                                         label=f' - Mehrfamilienhaus',
                                         unit='€/m²')

        def save():
            self.changed.emit()
            self.grst_settings.EFH_Rohmiete = round(
                self.rohmiete_params.efh.value * 100)
            self.grst_settings.DHH_Rohmiete = round(
                self.rohmiete_params.dhh.value * 100)
            self.grst_settings.RHW_Rohmiete = round(
                self.rohmiete_params.rhw.value * 100)
            self.grst_settings.MFH_Rohmiete = round(
                self.rohmiete_params.mfh.value * 100)
            self.grst_settings.save()

        self.rohmiete_params.show(title='Rohmieten bearbeiten')
        self.rohmiete_params.changed.connect(save)

    def setup_sachwert(self):
        '''
        asset value parameters
        '''
        tou = self.areas.values('nutzungsart')
        if not self.grst_settings.is_new_bundesland\
           or not Nutzungsart.WOHNEN.value in tou:
            self.ui.grundsteuer_sachwert_param_group.setVisible(False)
            return
        if self.sachwert_params:
            self.sachwert_params.close()
        self.ui.grundsteuer_sachwert_param_group.setVisible(True)
        layout = self.ui.grundsteuer_sachwert_param_group.layout()
        clear_layout(layout)
        self.sachwert_params = Params(
            layout, help_file='einnahmen_grundsteuer_sachwertverfahren.txt')

        self.sachwert_params.add(Title('Sachwertverfahren', bold=False))
        self.sachwert_params.bodenwert = Param(
            self.grst_settings.Bodenwert_SWV / 100,
            DoubleSpinBox(minimum=0.3, maximum=5, step=0.05),
            label=f' - Bodenwert 1935 pro m²',
            unit='€/m²')
        self.sachwert_params.flaeche = Param(
            self.grst_settings.qm_Grundstueck_pro_WE_EFH,
            SpinBox(minimum=300, maximum=2000, step=1),
            label=f' - mittl. Größe Einfamilienhausgrundstücke',
            unit='m²')

        def save():
            self.changed.emit()
            self.grst_settings.Bodenwert_SWV = round(
                self.sachwert_params.bodenwert.value * 100)
            self.grst_settings.qm_Grundstueck_pro_WE_EFH = \
                self.sachwert_params.flaeche.value
            self.grst_settings.save()

        self.sachwert_params.show(title='Sachwertverfahren bearbeiten')
        self.sachwert_params.changed.connect(save)

    def setup_bauvolumen(self):
        '''
        construction volume parameters
        '''
        tou = self.areas.values('nutzungsart')
        if not (Nutzungsart.GEWERBE.value in tou
                or Nutzungsart.EINZELHANDEL.value in tou):
            self.ui.grundsteuer_bauvolumen_param_group.setVisible(False)
            # set to 0 as a precaution to not put some old values into
            # the calculation
            self.grst_settings.Bueroflaeche = 0
            self.grst_settings.Verkaufsraeume = 0
            self.grst_settings.save()
            return
        self.ui.grundsteuer_bauvolumen_param_group.setVisible(True)
        if self.bauvolumen_params:
            self.bauvolumen_params.close()
        layout = self.ui.grundsteuer_bauvolumen_param_group.layout()
        clear_layout(layout)
        self.bauvolumen_params = Params(
            layout, help_file='einnahmen_grundsteuer_bauvolumen.txt')

        self.bauvolumen_params.add(
            Title(
                'Gewerbe / Einzelhandel: Voraussichtliches '
                'Bauvolumen\n(Brutto-Grundfläche, BGF)',
                bold=False))

        self.bauvolumen_params.bueroflaeche = Param(
            self.grst_settings.Bueroflaeche,
            SpinBox(minimum=0, maximum=99999, step=10),
            label=f' - Bürofläche',
            unit='m²')
        self.bauvolumen_params.verkaufsraeume = Param(
            self.grst_settings.Verkaufsraeume,
            SpinBox(minimum=0, maximum=99999, step=10),
            label=f' - Hallen und Verkaufsräume',
            unit='m²')

        def save():
            self.changed.emit()
            self.grst_settings.Bueroflaeche = \
                self.bauvolumen_params.bueroflaeche.value
            self.grst_settings.Verkaufsraeume = \
                self.bauvolumen_params.verkaufsraeume.value
            self.grst_settings.save()

        self.bauvolumen_params.show(
            title='Voraussichtliches Bauvolumen bearbeiten')
        self.bauvolumen_params.changed.connect(save)

    def calculate(self):
        '''
        calculate the property tax
        '''
        job = GrundsteuerCalculation(self.project)

        def on_success(r):
            self.add_layer()

        self.changed.emit()
        self.dialog = ProgressDialog(job,
                                     parent=self.ui,
                                     on_success=on_success,
                                     auto_close=True)
        self.dialog.show()

    def add_layer(self):
        '''
        show property tax layer
        '''
        self.output = ProjectLayer.from_table(self.gemeinden.table,
                                              groupname=self.layer_group)
        self.output.draw(label='Grundsteuer',
                         style_file='einnahmen_grundsteuer.qml',
                         filter="grundsteuer != 'NULL'",
                         uncheck_siblings=True,
                         redraw=False)
        self.output.zoom_to()

    def close(self):
        if self.hebesatz_params:
            self.hebesatz_params.close()
        if self.rohmiete_params:
            self.rohmiete_params.close()
        if self.sachwert_params:
            self.sachwert_params.close()
        if self.bauvolumen_params:
            self.bauvolumen_params.close()