Esempio n. 1
0
    def __init__(self, model, viewCode, model_admin, protoMeta  ):
            
        self.model = model              # the model to use as reference
        self.title = self.model._meta.verbose_name.title()
        
        # importa las definiciones del modelo y del admin 
        self.model_admin =  model_admin
        self.protoMeta =  protoMeta
        
        # garantiza la llave 
        self.viewCode = viewCode  

        # Inicializa  
        self.fields = []                
        self.fieldsDict = {}
        self.gridConfig = self.protoMeta.get( 'gridConfig', {})

        # Los campos deben ser inicialmente un diccionario para poder validarlos 
        protoMeta[ 'fields' ]  =  protoMeta.get( 'fields', [])
        if isinstance( protoMeta[ 'fields' ], list )  :  
            self.fieldsDict = list2dict( protoMeta[ 'fields' ], 'name')


        #UDPs para poder determinar el valor por defecto ROnly 
        self.pUDP = self.protoMeta.get( 'usrDefProps', {}) 
        verifyUdpDefinition( self.pUDP )

        # lista de campos para la presentacion en la grilla 
        pListDisplay = verifyList( self.gridConfig.get( 'listDisplay', []) )
        if not pListDisplay: 
            pListDisplay = verifyList( getattr(self.model_admin , 'list_display', []))

            # Por defecto solo vienen  Chk, _str_
            try: pListDisplay.remove('action_checkbox')
            except ValueError:  pass
    
            # if pListDisplay and (pListDisplay[0] == '__str__'): pListDisplay = []
            if len(pListDisplay) == 0: pListDisplay = [ '__str__' ]
            
        self.gridConfig['listDisplay'] = pListDisplay 
        
        
        # Se leen los excluidos del admin, no se requiere 
        # en la protoDef, pues los campos se enumeran explicitamente 
        protoExclude = verifyList( self.protoMeta.get( 'exclude', []))

        #Se leen los readonly fields para setear el attr readOnly = true 
        pReadOnlyFlds = verifyList( self.gridConfig.get( 'readOnlyFields', []) )
        if not pReadOnlyFlds:
            pReadOnlyFlds =  verifyList( getattr(self.model_admin , 'readonly_fields', []))   

        self.gridConfig['readOnlyFields'] = pReadOnlyFlds 

        # @@ Por alguna Ext no retiene el IdProperty ( idInternal al hacer click en las filas )     
        # idName = model._meta.pk.name   
        
        # La lista de campos del admin sirve de base, pues puede haber muchos mas campos en proto q en admin
        # Si solo queda el __str__ , asume todos los campos del modelo
        
#        iCount = len( pListDisplay )  
#        if ( iCount == 0  ) or ( iCount == 1 and (pListDisplay[0] == '__str__')) :

        # Se crean los campos con base al modelo ( trae todos los campos del modelo )
        for field in self.model._meta._fields():
            if field.name in protoExclude: continue
            setFieldDict (  self.fieldsDict , field )


#         for field in self.model._meta._many_to_many():
#             if field.name in protoExclude: continue
#             setFieldDict (  self.fieldsDict , field )

        # Agrega el __str__ que sirve de base para los zooms
        fName = '__str__' 
        fdict = self.fieldsDict.get( fName , {}) 
        if not fdict: 
            fdict['name'] = fName
            self.fieldsDict[ fName ] = fdict
            
            setDefaultField ( fdict, self.model, self.viewCode )
             

        # Genera la lista de campos y agrega el nombre al diccionario 
        for key in self.fieldsDict:        
            fdict = self.fieldsDict[ key ]
            if (fdict.get( 'name', '') == '') : fdict[ 'name' ] = key  

            if key in pReadOnlyFlds: fdict[ 'readOnly' ] = True

            # Repasa las propiedades de base, ver por q no esta pasando trayendo las props de base ( ie:  defaulValue )  
            if ( not ( key.startswith( 'udp__') )):
                try: 
                    field = self.model._meta.get_field( key )
                    setFieldDict ( self.fieldsDict , field )
                    fdict = self.fieldsDict[ key ]
                except: 
                    #Es posible q se puedan configuar propiedades no pertenecientes a la tabla como editables???
                    fdict[ 'readOnly' ] = True
                    pass 

            self.fields.append(fdict)
Esempio n. 2
0
def _protoEdit(request, myAction ):

    if not request.user.is_authenticated():
        return doReturn ({'success':False ,'message' : 'readOnly User'})

    if request.method != 'POST':
        return doReturn ({'success':False, 'message' : 'invalid message'})

    message = ''

#   Carga el modelo
    protoMeta = request.POST.get('protoMeta', '')
    protoMeta = json.loads( protoMeta )
    viewEntity = protoMeta.get('viewEntity', '')
    model = getDjangoModel(viewEntity)

#   Autentica
    if not getModelPermissions( request.user, model, myAction ):
        return doReturn ({'success':False ,'message' : 'No ' +  myAction +  'permission'})

#   Obtiene el profile para saber el teamhierarchi
    userProfile = getUserProfile( request.user, 'edit', viewEntity )

#   Verfica si es un protoModel ( maneja TeamHierarchy )
    isProtoModel = hasattr( model , '_protoObj' )

#   Verifica si hay registros que son solo de referencia
    userNodes = []
    refAllow = False 
    if myAction in ['delete', 'change'] and isProtoModel and not request.user.is_superuser  :
        refAllow = getModelPermissions( request.user, model, 'refallow' )
        if refAllow:
            userNodes = getUserNodes( request.user, viewEntity )

#   WorkFlow  
    hasWFlow = hasattr( model , '_WorkFlow' ) and isProtoModel 
    if hasWFlow: 
        wfadmin =  getModelPermissions( request.user , model, 'wfadmin' )
        WFlowControl = getattr( model, '_WorkFlow', {} )
        initialWfStatus = WFlowControl.get( 'initialStatus', '0')

#   Decodifica los eltos
    rows = request.POST.get('rows', [])
    rows = json.loads( rows )

    fieldsDict = list2dict( protoMeta[ 'fields' ], 'name')

#   JsonField
    jsonField = protoMeta.get('jsonField', '')
    if not isinstance( jsonField, (str, unicode) ): jsonField = ''

#   TOOD: Log
#   activityLog ( myAction, request.user , viewEntity,  {  'protoMeta' : protoMeta , 'rows' : rows })


#   Genera la clase UDP
    pUDP = protoMeta.get('usrDefProps', {})
    cUDP = verifyUdpDefinition( pUDP )

    # Verifica q sea una lista de registros, (no deberia pasar, ya desde Extjs se controla )
    if type(rows).__name__=='dict':
        rows = [rows]


    pList = []
    for data in rows:

        data['_ptStatus'] =  ''

        if myAction == 'add':
            rec = model()
        else:
            try:
                rec = model.objects.get( pk = data['id']  )
            except:
                data['_ptStatus'] = data['_ptStatus'] +  ERR_NOEXIST + '<br>'
                pList.append( data )
                continue


        # refAllow verifica si corresponde a los registros modificables  ( solo es true en myAction in ['delete', 'change'] ) 
        if refAllow and isProtoModel :
            if not ( str( rec.smOwningTeam_id ) in userNodes ) :
                data['_ptStatus'] = ERR_REFONLY + '<br>'
                pList.append( data )
                continue

        if not ( myAction == 'delete' ):
            # Upd, Ins
            for key in data:
                key = smart_str( key )
                if  key in ['id', '_ptStatus', '_ptId', '__str__']: continue

                vFld = fieldsDict[key]
                if vFld.get( 'crudType' )  in ["screenOnly", "linked" ]: continue

                #  Los campos de seguridad se manejan a nivel registro
                if isProtoModel:
                    if key in ['smOwningUser','smOwningTeam','smCreatedBy','smModifiedBy',
                               'smWflowStatus','smRegStatus','smCreatedOn','smModifiedOn',
                               'smOwningUser_id','smOwningTeam_id','smCreatedBy_id','smModifiedBy_id']: continue

                #  Udps
                if (cUDP.udpTable and key.startswith( cUDP.propertyPrefix + '__')): continue

                #  JsonField
                if key ==  jsonField: continue
                if key.startswith( jsonField + '__'): continue

                try:
                    setRegister( model,  rec, key,  data )
                except Exception as e:
                    data['_ptStatus'] = data['_ptStatus'] +  getReadableError( e )

            if isProtoModel:
                setSecurityInfo( rec, data, userProfile, ( myAction == 'add' ) )


            if len( jsonField ) > 0:
                jsonInfo = {}
                for key in data:
                    if not key.startswith( jsonField + '__'): continue
                    jKey = key[ len(jsonField) + 2 : ]
                    jsonInfo[ jKey ] = data[ key ]
                setattr( rec, jsonField , jsonInfo   )


            # Inicializa el estado del WF 
            if hasWFlow: 
                setattr( rec, 'smWflowStatus' , initialWfStatus )

            # Guarda el idInterno para concatenar registros nuevos en la grilla
            try:
                _ptId = data['_ptId']
            except:
                _ptId = ''

            try:
                rec.save()

                # Guardar las Udps
                if cUDP.udpTable:
                    try:
                        saveUDP( rec, data, cUDP  )
                    except Exception as e:
                        raise Exception( 'UdpError: saveActiob')

                # -- Los tipos complejos ie. date, generan un error, es necesario hacerlo detalladamente
                # Convierte el registro en una lista y luego toma solo el primer elto de la lista resultado.
                data = Q2Dict(protoMeta , [rec], False  )[0]
                data['_ptId'] =  _ptId

            except Exception as  e:
                data['_ptStatus'] =  data['_ptStatus'] +  getReadableError( e )
                data['_ptId'] =  _ptId
                #traceback.print_exc()
                #return doReturn ({'success':False ,'message' : str( e )})

        else:  # Action Delete
            try:
                rec.delete()

            except Exception,  e:
                data['_ptStatus'] = data['_ptStatus'] +  getReadableError( e )
                pass

        pList.append( data )

        if data.get('_ptStatus', ''):
            message += data['_ptStatus']  + ';'
def Q2Dict (protoMeta, pRows, fakeId, userNodes=[]):
    """
        userNodes : Para el manejo de refAllow : contiene los Id de los teams validos  
        return the row list from given queryset
    """

#    pStyle = protoMeta.get( 'pciStyle', '')
    JsonField = protoMeta.get('jsonField', '')
    if not isinstance(JsonField, (str, unicode)): 
        JsonField = ''

    pUDP = protoMeta.get('usrDefProps', {})
    cUDP = verifyUdpDefinition(pUDP)
    rows = []

    # Tablas de zoom para absorcion de campos
    relModels = {}

    # Identifica las Udps para solo leer las definidas en la META
    if cUDP.udpTable :
        udpTypes = {} 
        udpList = []
        for lField  in protoMeta['fields']:
            fName = lField['name']
            if fName.startswith(cUDP.propertyPrefix + '__'):
                udpList.append(fName)
                udpTypes[ fName ] = lField['type']


    # Alimenta la coleccion de zooms, por cada campo pues hay q hacer un select para esto
    for lField  in protoMeta['fields']:
        fName = lField['name']
        myZoomModel = lField.get('zoomModel', '')
        if (len(myZoomModel) > 0) and (myZoomModel != protoMeta['viewEntity']):
            relModels[ fName ] = { 'zoomModel' : myZoomModel, 'fkId' : lField.get('fkId', '') , 'loaded' : False }


    # Verifica si existen reemplazos por hacer ( cpFromField )
    # 1.  Marca los zooms q estan referenciados
    bCopyFromFld = False
    for lField  in protoMeta['fields']:
        fName = lField['name']
        if (lField.get('cpFromField') is None or lField.get('cpFromZoom') is None): 
            continue
        bCopyFromFld = True

        # Marca el campo
        lField[ 'isAbsorbed' ] = True

        # Marca el zoom
        try:
            relModel = relModels[ lField.get('cpFromZoom') ]
            relModel[ 'loaded'] = True
        except: 
            pass


    # 2.  borra los q no tienen marca
    for relName in relModels.keys():
        relModel = relModels[ relName ]
        if not relModel[ 'loaded']: 
            del relModels[ relName ]


    #   Esta forma permite agregar las funciones entre ellas el __unicode__
    rowId = 0
    for rowData in pRows:
        rowId += 1
        rowdict = {}

        # limpia los datos de tablas relacionadas
        for relName in relModels:
            relModel = relModels[ relName ]
            relModel[ 'rowData'] = {}
            relModel[ 'loaded'] = False

        # recorre los campos para obtener su valor
        for lField  in protoMeta['fields']:
            fName = lField['name']
            pName = lField.get('physicalName', fName)

            if lField.get('crudType') == "screenOnly" : 
                continue

            # UDP Se evaluan despues
            if cUDP.udpTable and fName.startswith(cUDP.propertyPrefix + '__'):
                continue

            elif (lField['type'] == 'protoN2N'):
                continue

            # Si el campo es absorbido ( bCopyFromFld es un shortcut para evitar la evulacion en caso de q no haya ningun cpFromField )
            elif bCopyFromFld and isAbsorbedField(lField, protoMeta) :
                continue

            rowdict[ fName ] = getFieldValue(pName, lField[ 'type'], rowData, JsonField)

        if cUDP.udpTable:
            # rowDict : se actualizara con los datos de la UDP
            # rowData es el registro de base, en caso de q sea un MD la lectura es automatica rowData.udpTable...
            # udpTypes  : lista de Udps a leer
            readUdps(rowdict, rowData , cUDP, udpList, udpTypes)


        # REaliza la absorcion de datos provenientes de un zoom
        if bCopyFromFld:
            rowdict = copyValuesFromFields(protoMeta, rowdict, relModels, JsonField)

#        Dont delete  ( Dgt ) 
#        if pStyle == 'tree':
#            rowdict[ 'viewEntity' ] = protoMeta.get('viewEntity', '')
#            rowdict[ 'leaf' ] = False; rowdict[ 'children' ] = []

        # Agrega el Id Siempre como idInterno ( no representa una col, idProperty )
        rowdict[ 'id'] = rowData.pk
        if fakeId:
            rowdict[ 'id'] = rowId


        # Verifica el refAllow 
        if len(userNodes) > 0  and  not (str(rowData.smOwningTeam_id) in userNodes) :
            rowdict['_ptStatus'] = REFONLY 
        
        # Agrega la fila al diccionario
        rows.append(rowdict)


    return rows
Esempio n. 4
0
def Q2Dict(protoMeta, pRows, fakeId, userNodes=[]):
    """
        userNodes : Para el manejo de refAllow : contiene los Id de los teams validos  
        return the row list from given queryset
    """

    #    pStyle = protoMeta.get( 'pciStyle', '')
    JsonField = protoMeta.get('jsonField', '')
    if not isinstance(JsonField, (str, unicode)):
        JsonField = ''

    pUDP = protoMeta.get('usrDefProps', {})
    cUDP = verifyUdpDefinition(pUDP)
    rows = []

    # Tablas de zoom para absorcion de campos
    relModels = {}

    # Identifica las Udps para solo leer las definidas en la META
    if cUDP.udpTable:
        udpTypes = {}
        udpList = []
        for lField in protoMeta['fields']:
            fName = lField['name']
            if fName.startswith(cUDP.propertyPrefix + '__'):
                udpList.append(fName)
                udpTypes[fName] = lField['type']

    # Alimenta la coleccion de zooms, por cada campo pues hay q hacer un select para esto
    for lField in protoMeta['fields']:
        fName = lField['name']
        myZoomModel = lField.get('zoomModel', '')
        if (len(myZoomModel) > 0) and (myZoomModel != protoMeta['viewEntity']):
            relModels[fName] = {
                'zoomModel': myZoomModel,
                'fkId': lField.get('fkId', ''),
                'loaded': False
            }

    # Verifica si existen reemplazos por hacer ( cpFromField )
    # 1.  Marca los zooms q estan referenciados
    bCopyFromFld = False
    for lField in protoMeta['fields']:
        fName = lField['name']
        if (lField.get('cpFromField') is None
                or lField.get('cpFromZoom') is None):
            continue
        bCopyFromFld = True

        # Marca el campo
        lField['isAbsorbed'] = True

        # Marca el zoom
        try:
            relModel = relModels[lField.get('cpFromZoom')]
            relModel['loaded'] = True
        except:
            pass

    # 2.  borra los q no tienen marca
    for relName in relModels.keys():
        relModel = relModels[relName]
        if not relModel['loaded']:
            del relModels[relName]

    #   Esta forma permite agregar las funciones entre ellas el __unicode__
    rowId = 0
    for rowData in pRows:
        rowId += 1
        rowdict = {}

        # limpia los datos de tablas relacionadas
        for relName in relModels:
            relModel = relModels[relName]
            relModel['rowData'] = {}
            relModel['loaded'] = False

        # recorre los campos para obtener su valor
        for lField in protoMeta['fields']:
            fName = lField['name']
            pName = lField.get('physicalName', fName)

            if lField.get('crudType') == "screenOnly":
                continue

            # UDP Se evaluan despues
            if cUDP.udpTable and fName.startswith(cUDP.propertyPrefix + '__'):
                continue

            elif (lField['type'] == 'protoN2N'):
                continue

            # Si el campo es absorbido ( bCopyFromFld es un shortcut para evitar la evulacion en caso de q no haya ningun cpFromField )
            elif bCopyFromFld and isAbsorbedField(lField, protoMeta):
                continue

            rowdict[fName] = getFieldValue(pName, lField['type'], rowData,
                                           JsonField)

        if cUDP.udpTable:
            # rowDict : se actualizara con los datos de la UDP
            # rowData es el registro de base, en caso de q sea un MD la lectura es automatica rowData.udpTable...
            # udpTypes  : lista de Udps a leer
            readUdps(rowdict, rowData, cUDP, udpList, udpTypes)

        # REaliza la absorcion de datos provenientes de un zoom
        if bCopyFromFld:
            rowdict = copyValuesFromFields(protoMeta, rowdict, relModels,
                                           JsonField)


#        Dont delete  ( Dgt )
#        if pStyle == 'tree':
#            rowdict[ 'viewEntity' ] = protoMeta.get('viewEntity', '')
#            rowdict[ 'leaf' ] = False; rowdict[ 'children' ] = []

# Agrega el Id Siempre como idInterno ( no representa una col, idProperty )
        rowdict['id'] = rowData.pk
        if fakeId:
            rowdict['id'] = rowId

        # Verifica el refAllow
        if len(userNodes) > 0 and not (str(rowData.smOwningTeam_id)
                                       in userNodes):
            rowdict['_ptStatus'] = REFONLY

        # Agrega la fila al diccionario
        rows.append(rowdict)

    return rows
Esempio n. 5
0
    def __init__(self, model, viewCode, model_admin, protoMeta):

        self.model = model  # the model to use as reference
        self.title = self.model._meta.verbose_name.title()

        # importa las definiciones del modelo y del admin
        self.model_admin = model_admin
        self.protoMeta = protoMeta

        # garantiza la llave
        self.viewCode = viewCode

        # Inicializa
        self.fields = []
        self.fieldsDict = {}
        self.gridConfig = self.protoMeta.get('gridConfig', {})

        # Los campos deben ser inicialmente un diccionario para poder validarlos
        protoMeta['fields'] = protoMeta.get('fields', [])
        if isinstance(protoMeta['fields'], list):
            self.fieldsDict = list2dict(protoMeta['fields'], 'name')

        # UDPs para poder determinar el valor por defecto ROnly
        self.pUDP = self.protoMeta.get('usrDefProps', {})
        verifyUdpDefinition(self.pUDP)

        # lista de campos para la presentacion en la grilla
        pListDisplay = verifyList(self.gridConfig.get('listDisplay', []))
        if not pListDisplay:
            pListDisplay = verifyList(
                getattr(self.model_admin, 'list_display', []))

            # Por defecto solo vienen  Chk, _str_
            try:
                pListDisplay.remove('action_checkbox')
            except ValueError:
                pass

            if len(pListDisplay) == 0:
                pListDisplay = ['__str__']

        self.gridConfig['listDisplay'] = pListDisplay

        # Se leen los excluidos del admin, no se requiere
        # en la protoDef, pues los campos se enumeran explicitamente
        protoExclude = verifyList(self.protoMeta.get('exclude', []))

        # Se leen los readonly fields para setear el attr readOnly = true
        pReadOnlyFlds = verifyList(self.gridConfig.get('readOnlyFields', []))
        if not pReadOnlyFlds:
            pReadOnlyFlds = verifyList(
                getattr(self.model_admin, 'readonly_fields', []))

        self.gridConfig['readOnlyFields'] = pReadOnlyFlds

        # @@ Por alguna Ext no retiene el IdProperty ( idInternal al hacer click en las filas )
        # idName = model._meta.pk.name

        # La lista de campos del admin sirve de base, pues puede haber muchos mas campos en proto q en admin
        # Si solo queda el __str__ , asume todos los campos del modelo

        #        iCount = len( pListDisplay )
        #        if ( iCount == 0  ) or ( iCount == 1 and (pListDisplay[0] == '__str__')) :

        # Se crean los campos con base al modelo ( trae todos los campos del modelo )
        # for field in self.model._meta._fields(): #only for django 1.4
        for field in self.model._meta.fields:
            if field.name in protoExclude:
                continue
            setFieldDict(self.fieldsDict, field)

        # Agrega el __str__ que sirve de base para los zooms
        fName = '__str__'
        fdict = self.fieldsDict.get(fName, {})
        if not fdict:
            fdict['name'] = fName
            self.fieldsDict[fName] = fdict

            setDefaultField(fdict, self.model, self.viewCode)

        # Genera la lista de campos y agrega el nombre al diccionario
        for key in self.fieldsDict:
            fdict = self.fieldsDict[key]
            if (fdict.get('name', '') == ''):
                fdict['name'] = key

            if key in pReadOnlyFlds:
                fdict['readOnly'] = True

            # Repasa las propiedades de base, ver por q no esta pasando trayendo las props de base ( ie:  defaulValue )
            if (not (key.startswith('udp__'))):
                try:
                    field = self.model._meta.get_field(key)
                    setFieldDict(self.fieldsDict, field)
                    fdict = self.fieldsDict[key]
                except:
                    # Es posible q se puedan configuar propiedades no pertenecientes a la tabla como editables???
                    fdict['readOnly'] = True

            self.fields.append(fdict)
def _protoEdit(request, myAction):

    if not request.user.is_authenticated():
        return doReturn({'success': False, 'message': 'readOnly User'})

    if request.method != 'POST':
        return doReturn({'success': False, 'message': 'invalid message'})

    message = ''

    #   Carga el modelo
    protoMeta = request.POST.get('protoMeta', '')
    protoMeta = json.loads(protoMeta)
    viewEntity = protoMeta.get('viewEntity', '')
    model = getDjangoModel(viewEntity)

    #   Autentica
    if not getModelPermissions(request.user, model, myAction):
        return doReturn({
            'success': False,
            'message': 'No ' + myAction + 'permission'
        })

#   Obtiene el profile para saber el teamhierarchi
    userProfile = getUserProfile(request.user, 'edit', viewEntity)

    #   Verfica si es un protoModel ( maneja TeamHierarchy )
    isProtoModel = hasattr(model, '_protoObj')

    #   Verifica si hay registros que son solo de referencia
    userNodes = []
    refAllow = False
    if myAction in ['DEL', 'UPD'
                    ] and isProtoModel and not request.user.is_superuser:
        refAllow = getModelPermissions(request.user, model, 'refallow')
        if refAllow:
            userNodes = getUserNodes(request.user, viewEntity)

#   WorkFlow
    hasWFlow = hasattr(model, '_WorkFlow') and isProtoModel
    if hasWFlow:
        wfadmin = getModelPermissions(request.user, model, 'wfadmin')
        WFlowControl = getattr(model, '_WorkFlow', {})
        initialWfStatus = WFlowControl.get('initialStatus', '0')

#   Decodifica los eltos
    rows = request.POST.get('rows', [])
    rows = json.loads(rows)

    #   LogInfo
    logEvent(viewEntity, rows, request.user, userProfile.userTeam, '',
             myAction)

    #   Fields
    fieldsDict = list2dict(protoMeta['fields'], 'name')

    #   JsonField
    jsonField = protoMeta.get('jsonField', '')
    if not isinstance(jsonField, (str, unicode)):
        jsonField = ''


#   TOOD: Log
#   activityLog ( myAction, request.user , viewEntity,  {  'protoMeta' : protoMeta , 'rows' : rows })

#   Genera la clase UDP
    pUDP = protoMeta.get('usrDefProps', {})
    cUDP = verifyUdpDefinition(pUDP)

    # Verifica q sea una lista de registros, (no deberia pasar, ya desde Extjs se controla )
    if type(rows).__name__ == 'dict':
        rows = [rows]

    pList = []
    for data in rows:

        data['_ptStatus'] = ''

        if myAction == 'INS':
            rec = model()
        else:
            try:
                rec = model.objects.get(pk=data['id'])
            except:
                data['_ptStatus'] = data['_ptStatus'] + ERR_NOEXIST + '<br>'
                pList.append(data)
                continue

        # refAllow verifica si corresponde a los registros modificables  ( solo es true en myAction in ['DEL', 'UPD'] )
        if refAllow and isProtoModel:
            if not (str(rec.smOwningTeam_id) in userNodes):
                data['_ptStatus'] = ERR_REFONLY + '<br>'
                pList.append(data)
                continue

        if not (myAction == 'DEL'):
            # Upd, Ins
            for key in data:
                key = smart_str(key)
                if key in ['id', '_ptStatus', '_ptId', '__str__']:
                    continue

                vFld = fieldsDict[key]
                if vFld.get('crudType') in ["screenOnly", "linked"]:
                    continue

                #  Los campos de seguridad se manejan a nivel registro
                if isProtoModel:
                    if key in [
                            'smOwningUser', 'smOwningTeam', 'smOwningUser_id',
                            'smOwningTeam_id', 'smCreatedBy', 'smModifiedBy',
                            'smCreatedBy_id', 'smModifiedBy_id', 'smCreatedOn',
                            'smModifiedOn', 'smWflowStatus', 'smRegStatus',
                            'smUUID'
                    ]:
                        continue

                #  Udps
                if (cUDP.udpTable
                        and key.startswith(cUDP.propertyPrefix + '__')):
                    continue

                #  JsonField
                if key == jsonField:
                    continue
                if key.startswith(jsonField + '__'):
                    continue

                try:
                    setRegister(model, rec, key, data)
                except Exception as e:
                    data['_ptStatus'] = data['_ptStatus'] + getReadableError(e)

            if isProtoModel:
                setSecurityInfo(rec, data, userProfile, (myAction == 'INS'))

            if len(jsonField) > 0:
                jsonInfo = {}
                for key in data:
                    if not key.startswith(jsonField + '__'):
                        continue
                    jKey = key[len(jsonField) + 2:]
                    jsonInfo[jKey] = data[key]
                setattr(rec, jsonField, jsonInfo)

            # Inicializa el estado del WF
            if hasWFlow:
                setattr(rec, 'smWflowStatus', initialWfStatus)

            # Guarda el idInterno para concatenar registros nuevos en la grilla
            try:
                _ptId = data['_ptId']
            except:
                _ptId = ''

            try:
                rec.save()

                # Guardar las Udps
                if cUDP.udpTable:
                    try:
                        saveUDP(rec, data, cUDP)
                    except Exception as e:
                        raise Exception('UdpError: saveActiob')

                # -- Los tipos complejos ie. date, generan un error, es necesario hacerlo detalladamente
                # Convierte el registro en una lista y luego toma solo el primer elto de la lista resultado.
                data = Q2Dict(protoMeta, [rec], False)[0]
                data['_ptId'] = _ptId

            except Exception as e:
                data['_ptStatus'] = data['_ptStatus'] + getReadableError(e)
                data['_ptId'] = _ptId
                # traceback.print_exc()
                # return doReturn ({'success':False ,'message' : str( e )})

        else:  # Action Delete
            try:
                rec.delete()

            except Exception, e:
                data['_ptStatus'] = data['_ptStatus'] + getReadableError(e)

        pList.append(data)

        if data.get('_ptStatus', ''):
            message += data['_ptStatus'] + ';'