import uuid from arches.app.functions.base import BaseFunction from arches.app.models.system_settings import settings from arches.app.models import models from arches.app.models.tile import Tile from arches.app.models.resource import Resource from django.db import connection, transaction import json import logging from datetime import datetime details = { 'name': 'Valor patrimonial', 'type': 'node', 'description': 'Calcula el valor patrimonial en base a ciertos descriptores y valores', 'defaultconfig': { "proteccion": { "valor_ndeId": "d385a291-6ed0-11ee-b4c9-911631b3a94c", "interesante_ndeId": "5162187a-f132-11ee-95c6-c93a5afc2c06", "valor_ndegrpId": "d385a293-6ed0-11ee-b4c9-911631b3a94c", "valor_tipo": ["val_proteccion"], "valor_tipo_indice": 0 }, "niveles": { "valor_ndeId": "c50d84f4-cdea-11ef-bee9-419cfc3bf4ec", "valor_ndegrpId": "9b8c37d8-cdea-11ef-bee9-419cfc3bf4ec", "valor_tipo": ['Urbana','Formal','Tipológico','Integridad'], "valor_tipo_indice": 2 }, "otros_patrimonio": { "valor_ndeId": "5d841086-7c2f-11ee-b432-e9e27a5b849b", "valor_ndegrpId": "5d841086-7c2f-11ee-b432-e9e27a5b849b", "valor_tipo": ["Inmaterial","Formal","Muebles","Natural"], "valor_tipo_indice": 3 }, "seccion_exterior": { "valor_ndeId": "0a0451d4-cdee-11ef-bee9-419cfc3bf4ec", "valor_ndegrpId": "f333aeab-7849-11ee-9872-197bdd009cf7", "valor_tipo": ['Artística','Arquitectónica','Tipológico','Integridad'], "valor_tipo_indice": 4 }, "seccion_interior": { "valor_ndeId": "7349a5b8-cdee-11ef-bee9-419cfc3bf4ec", "valor_ndegrpId": "d98ea571-7c15-11ee-9f9d-13533b0eb7ec", "valor_tipo": ['Artística','Arquitectónica','Tipológico'], "valor_tipo_indice": 5 }, "circulacion": { "valor_ndeId": "adf46dba-cdee-11ef-bee9-419cfc3bf4ec", "valor_ndegrpId": "1d6bad39-7c1b-11ee-9f9d-13533b0eb7ec", "valor_tipo": ['Artística','Tipológico'], "valor_tipo_indice": 6 }, "espacios_exteriores": { "valor_ndeId": "e14ac826-cdee-11ef-bee9-419cfc3bf4ec", "valor_ndegrpId": "a1871e49-7c1d-11ee-9f9d-13533b0eb7ec", "valor_tipo": ['Artística',], "valor_tipo_indice": 7 }, "valorizacion": { "valor_ndeId": "c72dae37-72c7-11ee-b797-2be08bcc2bc6", "valor_ndegrpId": "c72dae37-72c7-11ee-b797-2be08bcc2bc6", "valor_tipo": ['Urbana','Individual','De conjunto','Arquitectónica','Formal','Tipológico','Histórica','Artística','Integridad','Inmaterial','Simbólico','Natural','Muebles'], "valor_tipo_indice": 1 }, "valor_string_map": "{'val_final': 'Sin valor', 'rango':[1,25,50], 'val_total':0, 'val_proteccion': [0,0,0,0,0,0],"\ "'Urbana': [0,0,0,0,0,0,0,0], 'Individual': [0,0,0,0,0,0,0,0],'De conjunto': [0,0,0,0,0,0,0,0],"\ "'Arquitectónica': [0,0,0,0,0,0,0,0], 'Formal': [0,0,0,0,0,0,0,0], 'Tipológico': [0,0,0,0,0,0,0,0],"\ "'Histórica': [0,0,0,0,0,0,0,0], 'Artística': [0,0,0,0,0,0,0,0], 'Integridad': [0,0,0,0,0,0,0,0],"\ "'Inmaterial': [0,0,0,0,0,0,0,0], 'Simbólico': [0,0,0,0,0,0,0,0], 'Natural': [0,0,0,0,0,0,0,0],"\ "'Muebles': [0,0,0,0,0,0,0,0]}", "valor_total_id": "1d5b879a-cdec-11ef-bee9-419cfc3bf4ec", # Nodo para valor numérico calculado. Ej. 38 "valor_final_id": "0511276c-cdec-11ef-bee9-419cfc3bf4ec", # Nodo para valor literal por categoría. Ej. Valor B "rango_tipo_id": "c2974c7c-cdeb-11ef-bee9-419cfc3bf4ec", # Nodo para el rango, literal. Ej. [1,25,50] "factor_ajuste_id":"da4a038c-cdeb-11ef-bee9-419cfc3bf4ec", # Nodo para introducir un valor numérico de ajuste. "valor_tipo_id": "8747962c-cdeb-11ef-bee9-419cfc3bf4ec", # Nodo para valor_string_map, literal "triggering_nodegroups": [] }, "classname": "ValoracionPatrimonial", "component": "", "functionid":"d206bc88-1c17-4860-b70c-5db9af5ab603", } class ValoracionPatrimonial(BaseFunction): def get(self): raise NotImplementedError def valor_nodo_ponderable(self, tile, request, is_function_save_method=True): """ Función que calcula el valor patrimonial en base a descriptores específicos Args: self: Objeto código. tile: Tile al que se adjuntará/modificará el código. request: Solicitud WSGI para verificar que la llamada sea acción del usuario. La función finaliza en valor nulo. is_function_save_method: Un valor booleano que indica si la función que lo llama es la función de guardado. jbti - 10.4.25 """ if request is None and is_function_save_method == True: return valorDictMap={} conceptoValorSumar = {'00000000-0000-0000-7585-000000000000': [0, 'ElementoSinValor']} # estructura (ej.): {'id1':[2,'Urbano'],'id2':....} def format_string_value(id_string_value): languages = models.Language.objects.all() default_language = languages.get(code=settings.LANGUAGE_CODE) return {default_language.code: {"value": id_string_value, "direction": default_language.default_direction}} def limpiar_valores(preValorDictMap,indiceVal): for val in preValorDictMap: match val: case 'val_final' | 'val_total' | 'rango' | 'val_proteccion': pass case _: preValorDictMap[val][indiceVal] = 0 return preValorDictMap def calcular_valores_parciales(preValorDictMap): sumaParcial = 0 promElementos = 0 for val in preValorDictMap: match val: case 'val_final' | 'val_total' | 'rango': sumaTotal = 0 case 'val_proteccion': sumaTotal = preValorDictMap[val][0] numSecciones = preValorDictMap[val][2]+preValorDictMap[val][3]+preValorDictMap[val][4]+preValorDictMap[val][5] case _: sumaParcial = sumaParcial + preValorDictMap[val][1]+preValorDictMap[val][2]+preValorDictMap[val][3] promElementos = promElementos + preValorDictMap[val][4]+preValorDictMap[val][5]+preValorDictMap[val][6]+preValorDictMap[val][7] sumaTotal = sumaTotal + sumaParcial if numSecciones in (1,2,3,4): sumaTotal = sumaTotal + promElementos//4 #numSecciones preValorDictMap['val_total'] = sumaTotal match sumaTotal: case sumaTotal if sumaTotal < preValorDictMap['rango'][0]: valorFinalRango ="Sin valor" case sumaTotal if (sumaTotal >= preValorDictMap['rango'][0] and sumaTotal < preValorDictMap['rango'][1]): valorFinalRango = "Valor C" case sumaTotal if (sumaTotal >= preValorDictMap['rango'][1] and sumaTotal < preValorDictMap['rango'][2]): valorFinalRango ="Valor B" case sumaTotal if sumaTotal >= preValorDictMap['rango'][2]: valorFinalRango = "Valor A" case _: valorFinalRango = "Valor desconocido" if preValorDictMap['val_proteccion'][1] == 0: valorFinalRango = "Sin valor" preValorDictMap['val_final'] = valorFinalRango return preValorDictMap def escribir_valores(tileValFinal,preValorDictMap): tileValFinal.data[self.config['valor_total_id'] ] = int(preValorDictMap['val_total']) tileValFinal.data[self.config['valor_final_id'] ] = format_string_value(str(preValorDictMap['val_final'])) tileValFinal.data[self.config['rango_tipo_id']] = format_string_value(str(preValorDictMap['rango'])) tileValFinal.data[self.config['valor_tipo_id']] = format_string_value(str(preValorDictMap)) if str(tile.nodegroup_id) != self.config['valorizacion']['valor_ndegrpId'] : tileValFinal.save() return def extraer_concepto_valor(string_id_concepto,str_tipo_valor): if string_id_concepto is not None: qry = f""" SELECT v.value FROM values v INNER JOIN values vv ON v.conceptid = vv.conceptid WHERE v.valuetype='{str_tipo_valor}' AND vv.valueid='{string_id_concepto}' """ cursor = connection.cursor() cursor.execute(qry) valorConcepto = cursor.fetchone()[0] if valorConcepto is None: valorConcepto = 0 cursor.close() else: valorConcepto = 0 return valorConcepto def ponderar_elem_const(resourceinstanceID, fichaValorMap, idNGrpExterior, idNodoCambio, valoresDistribuidos, indiceValorMap): sumarValor = 0 nivelesElemconst = set() elemTiles = Tile.objects.filter(nodegroup_id=idNGrpExterior,resourceinstance_id=resourceinstanceID) def calculo_por_tile(valTile): elemValor = 0 cambioVal = 0 if idNGrpExterior in valTile.data and valTile.data[idNGrpExterior] is not None: if len(valTile.data[idNGrpExterior]) > 0 : elemValorId = valTile.data[idNGrpExterior][0] else: elemValorId = '00000000-0000-0000-7585-000000000000' if elemValorId not in conceptoValorSumar : conceptoValorSumar.update({elemValorId : [int(extraer_concepto_valor(elemValorId,'hiddenLabel')), str(extraer_concepto_valor(elemValorId,'prefLabel'))]}) elemValor = conceptoValorSumar[elemValorId][0] if idNodoCambio in valTile.data and valTile.data[idNodoCambio] is not None: cambioValId = valTile.data[idNodoCambio] if cambioValId not in conceptoValorSumar: conceptoValorSumar.update({cambioValId : [int(extraer_concepto_valor(cambioValId,'hiddenLabel')), str(extraer_concepto_valor(cambioValId,'prefLabel'))]}) cambioVal = conceptoValorSumar[cambioValId][0] return elemValor * cambioVal if len(elemTiles) > 0 : for otroTile in elemTiles: nivelesElemconst.add(otroTile.parenttile.tileid) if str(otroTile.tileid) != str(tile.tileid) : nivelesElemconst.add(otroTile.parenttile.tileid) sumarValor = sumarValor + calculo_por_tile(otroTile) sumarValor = sumarValor + calculo_por_tile(tile) if len(nivelesElemconst) > 0 : sumarValor = sumarValor // len(nivelesElemconst) else: sumarValor = calculo_por_tile(tile) if tile is not None: fichaValorMap['val_proteccion'][indiceValorMap - 2] = 1 else: fichaValorMap['val_proteccion'][indiceValorMap - 2] = 0 limpiar_valores(fichaValorMap,indiceValorMap) for valorDistribuido in valoresDistribuidos: if fichaValorMap['val_proteccion'][indiceValorMap -2] == 1: fichaValorMap[valorDistribuido][indiceValorMap] = sumarValor return fichaValorMap def ponderar_proteccion(proteccionTile,idNodoEsDeInteres,fichaValorMap,idNodoProteccion,indiceVal): if idNodoEsDeInteres in proteccionTile.data : match proteccionTile.data[idNodoEsDeInteres] : case True: fichaValorMap['val_proteccion'][1] = 1 case _: # False or None fichaValorMap['val_proteccion'][1] = 0 sumaValoresProteccion = 0 if idNodoProteccion in proteccionTile.data and proteccionTile.data[idNodoProteccion] is not None: listaValoresId = proteccionTile.data[idNodoProteccion] for valId in listaValoresId: if valId not in conceptoValorSumar: conceptoValorSumar.update({valId : [int(extraer_concepto_valor(valId,'hiddenLabel')), str(extraer_concepto_valor(valId,'prefLabel'))]}) sumaValoresProteccion = sumaValoresProteccion + conceptoValorSumar[valId][0] fichaValorMap['val_proteccion'][indiceVal] = sumaValoresProteccion return fichaValorMap def ponderar_niveles(nivelesTile,idNodoValorNiveles,fichaValorMap,valorDistribuido,indiceVal): if idNodoValorNiveles in nivelesTile.data : #and nivelesTile[0].data[idNodoValorNiveles] is not None: valorId = nivelesTile.data[idNodoValorNiveles] if valorId not in conceptoValorSumar: conceptoValorSumar.update({valorId : [int(extraer_concepto_valor(valorId,'hiddenLabel')), str(extraer_concepto_valor(valorId,'prefLabel'))]}) for valDistribuido in valorDistribuido: fichaValorMap[valDistribuido][indiceVal] = conceptoValorSumar[valorId][0] return fichaValorMap def ponderar_otros(otrosTile,idNGrpValorOtros,fichaValorMap,indiceVal): if idNGrpValorOtros in otrosTile.data and otrosTile.data[idNGrpValorOtros] is not None: listaValoresId = otrosTile.data[idNGrpValorOtros] for valId in listaValoresId : if valId not in conceptoValorSumar : conceptoValorSumar.update({valId : [int(extraer_concepto_valor(valId,'hiddenLabel')), str(extraer_concepto_valor(valId,'prefLabel'))]}) fichaValorMap[conceptoValorSumar[valId][1]][indiceVal] = conceptoValorSumar[valId][0] return fichaValorMap def ponderar_valorizacion(valorizacionTile,idNGrpValorizacion,fichaValorMap,indiceVal): if idNGrpValorizacion in valorizacionTile.data and valorizacionTile.data[idNGrpValorizacion] is not None: listaValoresId = valorizacionTile.data[idNGrpValorizacion] for valId in listaValoresId : if valId not in conceptoValorSumar : conceptoValorSumar.update({valId : [int(extraer_concepto_valor(valId,'hiddenLabel')), str(extraer_concepto_valor(valId,'prefLabel'))]}) if conceptoValorSumar[valId][1] != 'Sin valor patrimonial' : fichaValorMap[conceptoValorSumar[valId][1]][indiceVal] = conceptoValorSumar[valId][0] return fichaValorMap try: """Se carga el valor final (valorStrinMap) o se pone un valor predeterminado (0)""" if str(tile.nodegroup_id) != str(self.config['valorizacion']['valor_ndegrpId']): vfinalTiles = Tile.objects.filter(nodegroup_id=str(self.config['valorizacion']['valor_ndegrpId']), resourceinstance_id=tile.resourceinstance_id) if len(vfinalTiles) > 0 : # (Falta) Procedimiento para validar el valor final existente vfinalTile = vfinalTiles[0] if vfinalTile.data[self.config['valor_tipo_id']] is not None: valorDictMap = eval(str(vfinalTile.data[self.config['valor_tipo_id']]['es']['value'])) if len(valorDictMap['val_proteccion']) == 2 : valorDictMap = eval(str(self.config['valor_string_map'])) # Reinicio else: valorDictMap = eval(str(self.config['valor_string_map'])) else: valorDictMap = eval(str(self.config['valor_string_map'])) tilesCarac = Tile.objects.filter(nodegroup_id = 'c72dae1f-72c7-11ee-b797-2be08bcc2bc6', resourceinstance_id = tile.resourceinstance_id) if len(tilesCarac) == 0 : tileCarac = Tile.get_blank_tile_from_nodegroup_id('c72dae1f-72c7-11ee-b797-2be08bcc2bc6', tile.resourceinstance_id, None) tileCarac.save() else: tileCarac = tilesCarac[0] vfinalTile = Tile.get_blank_tile_from_nodegroup_id(self.config['valorizacion']['valor_ndegrpId'], tile.resourceinstance_id, tileCarac) else: vfinalTile = tile if vfinalTile.data[self.config['valor_tipo_id']] is not None: valorDictMap = eval(str(vfinalTile.data[self.config['valor_tipo_id']]['es']['value'])) if len(valorDictMap['val_proteccion']) == 2 : valorDictMap = eval(str(self.config['valor_string_map'])) else: valorDictMap = eval(str(self.config['valor_string_map'])) """ Pondera los valores según el nodo actualmente editado """ if tile.nodegroup_id == str(self.config['proteccion']['valor_ndegrpId']) : valorDictMap = ponderar_proteccion(tile, self.config['proteccion']['interesante_ndeId'], valorDictMap, self.config['proteccion']['valor_ndeId'], self.config['proteccion']['valor_tipo_indice']) elif tile.nodegroup_id == str(self.config['niveles']['valor_ndegrpId']) : valorDictMap = ponderar_niveles(tile, self.config['niveles']['valor_ndeId'], valorDictMap, self.config['niveles']['valor_tipo'], self.config['niveles']['valor_tipo_indice']) elif tile.nodegroup_id == str(self.config['otros_patrimonio']['valor_ndegrpId']) : valorDictMap = limpiar_valores(valorDictMap,self.config['otros_patrimonio']['valor_tipo_indice']) valorDictMap = ponderar_otros(tile, self.config['otros_patrimonio']['valor_ndeId'], valorDictMap, self.config['otros_patrimonio']['valor_tipo_indice']) elif tile.nodegroup_id == str(self.config['valorizacion']['valor_ndegrpId']) : valorDictMap = limpiar_valores(valorDictMap,self.config['valorizacion']['valor_tipo_indice']) valorDictMap = ponderar_valorizacion(tile, self.config['valorizacion']['valor_ndeId'], valorDictMap, self.config['valorizacion']['valor_tipo_indice']) elif tile.nodegroup_id == str(self.config['seccion_exterior']['valor_ndegrpId']) : valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['seccion_exterior']['valor_ndegrpId'], self.config['seccion_exterior']['valor_ndeId'], self.config['seccion_exterior']['valor_tipo'], self.config['seccion_exterior']['valor_tipo_indice']) elif tile.nodegroup_id == str(self.config['seccion_interior']['valor_ndegrpId']) : valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['seccion_interior']['valor_ndegrpId'], self.config['seccion_interior']['valor_ndeId'], self.config['seccion_interior']['valor_tipo'], self.config['seccion_interior']['valor_tipo_indice']) elif tile.nodegroup_id == str(self.config['circulacion']['valor_ndegrpId']) : valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['circulacion']['valor_ndegrpId'], self.config['circulacion']['valor_ndeId'], self.config['circulacion']['valor_tipo'], self.config['circulacion']['valor_tipo_indice']) elif tile.nodegroup_id == str(self.config['espacios_exteriores']['valor_ndegrpId']) : valorDictMap = ponderar_elem_const(tile.resourceinstance_id, valorDictMap, self.config['espacios_exteriores']['valor_ndegrpId'], self.config['espacios_exteriores']['valor_ndeId'], self.config['espacios_exteriores']['valor_tipo'], self.config['espacios_exteriores']['valor_tipo_indice']) valorDictMap = calcular_valores_parciales(valorDictMap) escribir_valores(vfinalTile, valorDictMap) return except Exception as e: self.logger.error(e,"\t*** Fallo al actualizar la ponderación") return def save(self, tile, request, context=None): self.logger = logging.getLogger(__name__) print("\n\t*** llamado a la función ponderar.save ***") self.valor_nodo_ponderable(tile=tile, request=request, is_function_save_method=True) return def post_save(self, *args, **kwargs): raise NotImplementedError def delete(self, tile, request): raise NotImplementedError def on_import(self, tile): raise NotImplementedError def after_function_save(self, tile, request): raise NotImplementedError