• Este debate está vacío.
Viendo 8 entradas - de la 1 a la 8 (de un total de 8)
  • Autor
    Entradas
  • #31574
    Javier Ader
    Participante

    Buenas. Hace un tiempo venimos desarrollando junto con Luis Castelat de STI Cuyo nuevos InfoProdruct e InfoBParterns, ya nos presentaba bastantes limitaciones, principalmente de tiempo de respuesta (una base de con 15000 productos y 2000 ECs) y de utilidad para el usuarios final (principalmente porque es mucho mas comun buscar por conceptualmente por “or”, y setear un solo campo de busqueda). Bueno, las modificaciones empezaron a hacerse bastante grandes y se requierio una rescritura casi copleta de los Info actuales.
    Las caracteristicas pricipales que tienen son:
    -paginación: los resultados son paginados; acutlemtne simpre se hace de a 100 (hay otras limitaciones, como por ej, uno solo puede pasar a la sig. o anterior pagina; estas son mejoras a hacer)
    -subpanel de detalles: se agrego un subpanel de detalles que muestra en formato de texto detalles del item seleccionado (en reaidad, es html, asi que el formateo que se puede dar a la información es pontecialmente bastante versatil). Los datos que se muestran en la tabla y en el panel de detalle puede o no ser los mismos (por ej, en InfoBpartner se muestra en detlle la cat. de iva, algo que no se muestra en la tabla).

    -“recuerdo” de ancho de columnas y de tamaño de ventana: esto es algo que es bastante molesto a mi entender en los info actuales; un en general ensancha una columna porque esta demasiado chica y no deja ver la información; la proxima vez que se habra el Info especifico uno tiene que hacerlo de nuevo.

    -busquedas OR: un solo campo de texto y varios checbox (por defecto siempre seleccionados) que especifican en que campos buscar. La idea es que el usuario final abrá el info, ingrese el texto, de enter, y listo. En realidad esto permite que la mayoria de las busquedas se hagan en 5 pasoa de teclado: ingresa texto de busqueda, enter (inicia la busqueda y muestra los resultados), “flecha hacia abajo” para saltar del campo de texto a la primer fila del resultado, selección de la fila correspondiente, enter (selecciona el item y cierra el info).

    -por diseño, veo posible que sea incluso parametrisables desde diccionario de datos hasta cierto punto. El punto principal de modificación de que datos se muestran (tanto en las columnas de la tabla como en el supanel de detalle) se da en InfoXXXX.createLayoutInfo, que retorna un lista de descriptoes de “columnas” (List); si se logra mantener en la base de datos una representación de Info_ColumnNew (esta compuestos por datos simples; string, booleanos, enteros, etc), se podria parametrizar, al menos deberia ser relativamnte facil agregar nuevas columnas o detalles. La complicación vienen por el lado de la paramtrizacion de los parametros de busquedas.

    Bueno, pongo un par de scrennshots, el código y un par de observaciones mas:
    [img]http://www.eltita.com.ar/libertya/InfosNew-v1.00/InfoBpartern-libertya.JPG[/img]
    [img]http://www.eltita.com.ar/libertya/InfosNew-v1.00/infoProd-libertya.JPG[/img]

    Codigo:
    http://www.eltita.com.ar/libertya/InfosNew-v1.00/files-v1.00-23oct10.zip

    Observaciones finales:
    TODO:
    -manejar de manera correcta la iteracción en el thread de acceso a base de datos y la gui (el thread de despacho de eventos); esa es una deficiencia que tienen actualmetne todos los info y que lleva a que dos por tres la GUI se tilde.
    -Las subclases de InfoProduct no funcionan; en particular para productos con atributos. En realidad, esa subclase deberia ser reescrita. Tamien puede haber problemas con la subclases de InfoProduct en version TPV (aunque desde el TPV es de todas maneras usable)
    -el InfoBPartner NO selecciona la una dirección del la EC; eso “rompe” muchos callouts que asumen que este Info siempre setea este valor. Las mofificaciones de estos callouts son, de todas maneras simples y faciles de econtrar (hay que buscar referencias a Env.TAB_INFO ); cualuqier cosa pongo como modifique algunos. La otra opción es que InfoBparnter muestre las direcciones en una pequeña subtabla; y que permita al usuario seleccionar alguna de las direcciones (igual, este cambio pienso que habria que hacerlo de manera general, para permitir “subtablas” en general)
    -InfoProduct tal como esta, no va a compilar… esto es porque tiene un boton de “edicion de precios” y una referencia a otra clase que permitir hacer esto directamente desde el Info. Se deberia editar o comentar estas lienas (cualquier cosa avisen; son dos o tres lineas)
    -finalmente: hay mucho codigo repetido entre InfoBPartner e InfoProduct; se requiere hacer un refactoring y subir mucho de este código a superclase. Para mi gusto, pienso que estas modificaciones habrían que hacerla sobre todos los info (es decir, agregar paginación y supnael de detalles, al menos), por lo tanto mcuho de este codigo podría ir directamente sobre la clase Info (haciendo de paso un reescritura general de esta clase).

    Bueno, si alguien lo quiere probar y encuentra problemas o tiene alguna duda/comentario, pregunten. La idea seria que estos cambios queden en algún próximo release oficial (el código debería madurar un poco… pero la idea pienso que esta).

    #35122
    Federico Cristina
    Superadministrador

    Muchisimas gracias por vuestro aporte. En cuanto me haga un tiempo lo veo en detalle. Toda mejora siempre es bienvenida para ser incorporada en un nuevo release.

    Saludos!

    #35123

    Muy interesante! gracias por compartirlo.

    #35128

    Mas que interesante !

    Para poder incorporarlo al core, habría que pulir los temas que mencionas.

    Es interesante ademas, la posibilidad de parametrizar los info, ya que en algunos lugares se requerirán determinadas columnas y en otros, otras…

    Los invito a pensar un poco mas en ese sentido para encontrar una solucion superadora….

    Piensen en lo siguiente:
    Un usuario que está realizando una compra de un producto, necesita ver los precios, la cantidad “ordenada” (pedida) , el stock actual y la cantidad reservada para poder tomar la decision de comprarlo o no.
    Un usuario que esta realizando una venta, solo necesita ver la cantidad disponible y el precio de venta.
    Un usuario que está haciendo una transferencia entre depositos, no tiene porque ver ningun precio.

    Esto quiere decir, que el infoProduct debería poder ser parametrizado según su contexto.

    Se me ocurren varios enfoques para esto…
    1) Por perfil:
    Que se pueda indicar el comportamiento de los info según el perfil… podría ser una tabla mas con alguna info asociada al perfil. Si no se especifica nada, se usa el valor por defecto…
    Ventaja: Maxima flexibilidad y seguridad ya que no se permite al usuario ver lo que no debe/necesita.
    Desventaja: No es posible customizar el info, para el mismo perfil, en diferentes ventanas con diferente comportamiento (es esto necesario?)

    2) Por ventana:
    Sería algo asi como agregar información extra en el diccionario cada vez que indico una referencia que va a utilizar un info. Pordría ser mediante una tabla adicional donde se den de alta las diferentes “configuraciones de info”. Luego en el diccionario al indicar , por ejemplo una referencia a un M_product_ID , habrá que pedir que se indique a cual “configuracion de Info” se desea apuntar.
    Ventaja: Permite customizar el info para cada ventana.
    Desventaja: No permite que diferentes usuarios vean cosas diferentes en la misma ventana. Hay que ver como se resuelve cuando no se trata de una ventana (TPV, Cobros/Pagos, etc) ya que ahi no hay donde configurarlo.

    3) Por perfile/Ventana:
    La combinacion de ambos sería factible… pero me parece que demasiado compleja. Igual lo dejo como una alternativa superadora de ambas.

    Esta “configuración de Info” , mas alla de cómo se determina cual usar (por ventana, por perfil, etc), debería ser suficientemente potente para:
    [li]Tener parametros que indiquen las columnas, los filtros y algunas restricciones (tal vez en formato de where ?…esto se podría sacar de la logica de validacion del diccionario )
    [/li]
    [li]Tener la posibilidad de indicar subclases del info o directamente clases info alternativas, de manera de que cada uno pueda hacerse “su propio info” en caso de quererlo.[/li]

    Por ultimo y no menos importante, hay que tener en cuenta la compatibilidad y se debería poder incluir esto de la mejor manera para un minimo impacto. Esto es, en lo posible, todos los cambios deberían ser de manera tal que si no se hace nada (no se crean configuraciones, etc. y el diccionario no se actualiza para un info, por ejemplo) la aplicacion siga funcionando con el actual comportamiento. Es decir, que haya valores por defecto que permitan hacer la configuración de infos de manera gradual.

    Los invito a discutir respecto del tema, pensandolo de la manera mas amplia posible: Un nuevo esquema de manejo de ventanas Info dentro de la aplicación.

    #35124
    Javier Ader
    Participante

    (este post iba a ser mas largo y explicativo… pero se me corto la luz…. despues, en cuanto me haga un poco de tiempo libre, hago un documento en pdf explicando un poco mas la idea y lo subo)
    Bueno me habia quedado pensando en lo que planteo Antonio y lo retome porque pienso que la idea que se puede aplicare no solo Infos si no en general a otros tipos de ventanas que muestren pequeños busquedas/reportes (no necesariameten contra una tabla simple; si no algo en general).
    Mi idea ataca a las dos formas de customizacion que planteo Antonio; la primera parte (acceso en relacion a perfiles) no requiere modificar tablas existens (obviamente si requiere agregar tablas y relativamente bastante codigo); la segunda requiere que se modifique AD_Column para que en el caso de que el tipo sea TableDir (esto es, el tipo que se mapea al control que permite disparar un InfoXXX), se permita agregar que “columnas externas” (depues explico un poco mas esto) se van a mostrar.

    Las tablas seria basicamentge
    -AD_Info: tiene bastantes cosas, pero la mas importante es una AD_Table_ID; esto es para saber que AD_Info usar en un determinado Lookup; de toadas maneras pienso que no requerir que sea NOT NULL; en realidad estas AD_Info puede usarse para pequeñas ventanas que no esten asociadas a una tabla en particular. Tampoco se requiere que AD_Table_ID sea unico, pero pienso que deberia NO ser necesario hacer mas una para una determinada tabla; la razón es que el control a nivel de perfil se da a nivel de que columnas se muestran (igual agregar tambien controal de acceso a este nivel no traeria mayores problemas).
    Otro dato importante son : la sentencia sql “interna”, y el alias sobre esta. Si miran el codigo van a ver que las sentencias sql finales toman la forma

    Code:
    Select FROM
    ( SELECT INTERNO
    WHERE INTERNO — depende de los parámetros de búsqueda, de “sql dinamico” que tiene el Tabledir, y posiblemente de las las restricciones “Role.addAccess”
    ORDER BY ALGO — esto es requerido para que la paginación sea consistente
    LIMIT X, OFFSET Y — esto aplica la paginación, actualme siempre en salto de 100
    ) AS NombreTablaExterna — este nombre es al que me refiero como “alias”

    Un determinado AD_Info tiene uno o mas AD_InfoColumn; estas AD_InfoColumns son las que se van a usar para inferir lo que llame .

    -AD_InfoColumn: esta es la representación en diccionario de datos de lo que en el código definí con la clase Info_ColumnNew (el “New” porque la clase Info_Column ya existia…). Los datos mas importantes son : la clase de “resullSet”(la clase con que se tiene que leer desde la base de datos) como la clase con que se muestra en el grid (esta clase sirve por ej para distinguir entre el conjunto de AD_InfoColumn cual va a ser la que va a tener el “id” de la entidad siendo mostrada; esto es necesario para saber que columna es la que tiene por ej, el M_Product.M_Produt_ID en InfoProduct); si se tiene que mostrar en el grid y en que posición “relativa”; si se tiene que mostrar en el panel de detalle y en que posición “relativa”; la posición relativa en el resultSet (“relativa” significa que lo importante es el orden entre las varias AD_InfoColumn dentro de una determinada AD_Info; desde codigo, esto luego se normaliza a secuencias de la forma 1,2,3,4… o 0,1,2,3…. según sea el caso), y finalmente una expresión de columna sql arbitraria (eso si, la expresión usada para calculara tiene que hacer referencia “NombreDeTablaExterna”, no al nombre de la tabla que se haya usado internamente ). Esta ultima expresión es la que va a ir parar como un elemento en y por defecto NO tiene que tener parametros sql (si se requieren parametros, se tiene que poner dentro de la expresion sql interna; no en la expresion de las columnas).
    Ademas, hay que agregar un campo Value (esto es para la customizacion a nivel de ventanas; explico mas adelante), y otras que son mas cosméticas (ancho preferido de las columans; nombre corto en las columnas; tooltip).

    -AD_InfoColumnAccess : esta es simplemente una relación de acceso entre roles y AD_InfoColumn. Como todos estos tipos de acceso la semantica es: si no hay ninguna restricción sobre un AD_InfoColumn, entocnes todos tienen acceso; si hay uno o mas SOLO los Roles especificados tienen acceso. La columnas importantes serian las obvias: AD_COlumnInfo_ID y AD_Role_ID (posiblemente también IsActive)

    Ahora bien, el tema del “filtrado por contexto”, funciona agregando una sola columna string a AD_Column (se podría crear oooootra tabla solo para esto, pero no lo veo muy necesario) y “creando una convención” de filtrado. Llamemosle a esta columna InfoColumnFilter. La semantica detras del valor de esta string prodria ser:
    -vacia, null o “*”, no se filtran ninguna
    -“+CalueInfoColumn1,ValueInfoColumn2, etc” : se muestra SOLO las columnas que tengan estos “ValueInfoColumnX” en su “value”.
    -“-ValueInfoColumn2,ValueInfoColumn2, etc” : se muestran todas las columnas salvo las que tengan un Value especificados en la lista
    Esto es, la primer forma es “sin restricción”, la segunda (la que tiene prefijo +) es “sola estas”; la tercera (prefijo -), todas menos las que especifico.

    Bien; el algoritmo de “restricción” seria mas o menos
    1) Obtentgo el AD_Info (filtrando por AD_Table_ID)
    2) Obtento todas sus AD_InfoColumn (menos la inactivas) relacionadas al AD_Info (filtrando por AD_Info_ID obtenido en 1)
    2) Filtro la AD_InfoColumn segun el rol actual (este paso y el anteriro se puede hacer usando una sola sentencia sql; y en realidad queda mas claro hacerlo asi.
    Conceptualmente la sentencia sql seria

    Code:
    select * from AD_infoColumn IC
    where (
    O AD_InfoColumnAcces no tiene registrro para AD_InfoColumn
    O AD_InfoColumnAccess tiene una entrada para AD_infoCOlumn y el id del rol actual
    )
    AND IsActive = ‘Y’ AND AD_Info_ID =

    Esto básicamente obtiene una lista de InfoColumn_New; tomando esta lista y el filtrado de acceso a info (el cual la clase VLookup pasa como parametro al InfoXXXX), se consigue otra lista aplicando el filtrado de “contexto”. Esto es, esta lista final, previa “normalización” de indices (indices en resulset, que comienza en 1; e indices en “grid” y en “panel” de detalles que que comienzan en 1). Va a ser la que finalmente , forme las en el sql final.

    A esto, se le agrega un par de cosas mas que actualmente no estan soportadas y “deberia salir andado”. En particular la ordenación: el tema aca es que el ordenamiento se tiene que dar ANTES de aplicar la paginación, si no no tiene sentido (no tiene sentido ordernar mediante ; se tiene que hacer sobre las columnas que resueltan del select interno).
    Para esto, pienso que hay que agregara a AD_Info otra columna, tambien una string que tambien siga una convención simple. Lo mas simple que veo eso esto:
    OrderAvailables::Columna;: Columna2>, etc.
    Con esta string la GUI puede generar un pequeño control visual que le permita al usario aplicar el ordenamiento.

    Doy un ejemplo para que quede mas claro: info para MBParner:
    AD_Info:

    Code:
    AD_Table_ID:Id de AD_Table_id de C_BParner
    InnerSql: “SELECT * FROM C_BPartner”
    NameExternSelect: “EC”
    OrdersAvailables:”Nombre:C_BPartner.Name;CUIT:C_BPartner.CUIT”
    LimitPagination: 100
    (notese que OrdersAvaliable depende de la como se conforme InnserSql)

    Algunos AD_InfoColumn

    Code:
    AD_InfoColumn1:
    -value:Id
    -Class: “ID”
    En grid: si, en detalles, no
    -Orden visual: en grid 1, en detalles 0 (si no va en detalles este valor no se va a usar),
    -orden result set: 10
    -ExternCol : “EC.C_BPartner_ID as ID” (el as no es strictametne necesario)
    (notense que el externCol uiliza EC; esto es, AD_Info.NameExternSelect)

    AD_InfoColum2:
    -Value: Name
    -Class: String
    -En grid, si, en detalles, si
    -orden: en grid 20, en detales 20
    -orden result set: 20
    -ExtenrnCol: “EC.Name as Name”

    AD_InfoColumn3:
    -Value:CUIT
    -Class: String
    -En grid, si, en detalles , si
    -orden visual ; en grid 30, en detalles 30
    -orden result set: 30
    -ExternCol:”EC.CUIT as CUIT”

    AD_InfoColumn4:
    -Value:TaxIVA
    -Class:String
    -En Grid, NO, en detalles , si
    -orden visual: en grid 0; en detalles 40
    -orden result set: 40
    -ExternoCol :
    “(Select Name form C_TaxCategory where C_TaxCategory_ID = EC.C_Tax_Category_ID) AS CatIVA”
    (notese que esta ultima columna externa es calculada; pero es calculada a partir de EC.C_Tax_Category_ID; NO de C_BPartner.C_BPartner_ID;

    Bueno, en que sql resultaria todo esto? Asumiendo que no hay fitlrado por rol ni por contexto y que esta visulaizando la segunda pagina, ordenana por nombre (por defecto se ordena por la primer entrada en “OrdersAvailables”, la sentencia final seria algo asi

    Code:
    SELECT
    EC.C_BPartner_ID as ID,
    EC.Name as Name,
    EC.CUIT as CUIT,
    (Select Name form C_TaxCategory where C_TaxCategory_ID = EC.C_Tax_Category_ID) AS CatIVA
    FROM
    –aca viene el select interno, el filtrado, el orden y la paginación
    (
    SELECT * FROM C_BPartner — select interno
    WHERE xxxxx — este valor depende de los paramtros de busqueda
    ORDER BY Name — este se toma de alguna de las opciones en OrdersAvailables
    LIMIT 100, OFFSET 99 — limit se toma de AD_Info; offset del estado interno del Info haciendo simplemente la cuneta (LIMIT * pagina que se quiere ver) – 1
    ) AS EC — este es el “alias” tomado de AD_Info

    Con el resultado de esta query, y los datos dados en la lista normalizada de InfoColumn_New formada a partir de las AD_InfoColumns se puede mapear cada uno de los valores a sus respetivas posiciones tanto en el grid como en el panel detalle.

    Notese:
    1) el sql interno puede ser realmente complejo; puede ser tranquilamnete un “join” un “union” de varias tablas.
    2) lo unico que se cambia entre busqueda y busqueda y que depende de los parametros de busqueda, es WHERE xxxx; este WHERE xxx contiene tanto el filtrado del usuario, como el filtrado “dinamico” de los table dir (validación de table) como las restricciones de acceso dadas a un permir sobre determinadas filas de determinadas talbas (ver MRole.addAccessRole(String); a metodo hay que llamarlo con el sql intenro, NO con el sql final)
    3) Actualmente la logica de paginación no contempla retonrar el total de items “sin paginación” ; esto es facil de agregar haciendo el acceso en dos pasos: el primer generar una string final interna sin paginación y “redondeada” por un “SELECT Count(*)”; esto es algo como

    Code:
    SELECT COUNT(*) FROM
    (SELECT INTERNO CON WHERE xxx , pero sin ordenamiento ni LIMIT y OFFSET) AS NombreExterno

    Este select no calcula las columnas externas, ni las ordenas; solo aplica el WHERE xxx a la sql interna y al resultado de esto le obtiene la cantidad.

    4) Todas estructuras de datos y la logica detras no tiene porque estar estrictamente asociada a un InfoXXXX en particular. Es facil utilizar todo esto para ventanas de consultas en general ; digamos, ver las facturas adeudadas. Utilizando esta estructra se puede generar rapidamente un “form” que tenga casi todo el trabajo echo por este miniframework diseñado originalmente para Info’s. De aca que AD_Info.AD_Table_ID pueda ser null (esto es, no esta necesariamente asociada a una tabla).

    5) Siguiendo la idea de 4, a los infos o estas ventanas de consulta rapida, se les puede agregar reportes jasper “on the fly” (aunque aca no se si es tan facil) que tome como dataSource algo generado por la misma sql final (posiblemente sin paginación). El formato del reporte puede ser, a falta de otra informacion, de un formato por defecto; incluso con opciones simples como “mostrar tambine los detalles?”; “imprimir información de parametros?”. Fijense que hay bastante información como para generar un reporte Jasper generico (ancho de columnas, clases, si esta en detalle, si esta en el grid)

    6) Uniendo 4 y 5 se logra algo que para mi puede darle a todo esto mucho más valor agregado: se elimina para muchos escenarios el reporteador interno, con la siguientes cualidades:
    -uno tiene un preview directo (piensen el resultado de una busqueda de una InfoXXXX como un preview de que datos se van a imprimir)

    -uno puede “reejecutar” todo el informe sin que siquiera se invoque a Jasper (porque lo que un hace es en realidad reejecutar la query y ve los resultados en una grilla Java)

    -los parámetros no se piden de entrada; el usaurio los va probando y reejecutando la busqueda hasta que logra haber listado lo que realmente quiere reportear. Recién ahi apreta un boton “Print” (de aca en mas entra Jasper y el reporte generado al “vuelo”; lo unico que hay que darle es o la sentecia sql final, o directamente el resultSet)

    Ok, 5 y 6 se van un poco de las manos, pero no lo veo para nada imposible y faltaría para igualar al reporteador interno actual, la habilidad de “zoom”. Esto creo que se puede hacer fácilmente via la columna “class” en AD_InfoColumn; por ej, una convención es que la “clase” ID_XXXX es de tipo entero y en realidad refiere a un id de la tabla XXXX; por ej, si el InfoProduct (o en un reporte de productos en general) aparece una columna (una AD_InfoColumn) con clase “ID_C_TaxCategory”, toda la lógica lo trata como un entero (y en general no lo visualiza, ni el grid ni el detalle), pero al seleccionar una determinada fila se activan botones de zoom (con un nombre descriptivo), uno por cada ID_xxx que se haya encontrado en el proceso de generación las InfoColumn_New; si el usuario presiona el botón zoom asociada ID_TaxCategory, se busca el valor asociado con la fila actual y se invoca el el método de zoom correspondiente para la tabla “C_Tax_Category” con el valor encontrado). Esto ultimo esta bueno independientemente de se implementa 5 y 6 ya que sirve para los Info.

    Que opinan?

    PD : bueno, termine escribiendo mas de que antes de que se me corte la luz….

    #35346

    Javier
    Se ve muy interesante y prometedor el tema. seria bueno acotarlo a algo que pueda ser terminado e integrado al core de Libertya.
    Seria interesante plantear una serie de etapas de manera de ir integrando la funcionalidad de a poco y evitar que por ampliar demasiado el Scope del cambio no se termine haciendo nada.
    Cuales serian las etapas razonables según lo ves ? Podemos tener rapidamente un cambio que permita al menos comenzar a usar el paginado ?

    Saludos
    Antonio.

    #35357

    Javier, una consulta.

    Las info que programaron, son compatibles con la vista matricial que agregó el plugin de curva DetalleColor? o se puede aplicar estos cambios sobre dicho avance??

    Gracias!

    #35125
    Javier Ader
    Participante

    Mmm la verdad que no se, en principio todavía no lo probe para 10.09 (pero debería andar, ya que el infoProduct de esta versión no cambio con respecto a 10.03); el tema es que en 10.03 NO anda para para productos con instancias de producto (la ventana info para productos con instancias la muestra otra clase distinta, que hereda de InfoProduct; como modificamos InfoProduct algo se termino rompiendo), por lo tanto para este tipo de productos tampoco va a andar en 10.09.
    Supongo que este plugin hace uso de instancias de producto, asi que te va a traer problemas (ahora bajo el plugin y miro que hace más o menos).

    Si te interesa intentamos hacer las modificaciones, pero no las veo simples…
    Ok, en la solución “generica” que plantie tampoco avance (anduve medio complico en otras cosas) y no creo que logre salir en el futuro próximo, asi que tal vez valga la pena hacer el esfuerzo de que al menos para los productos con instancias y EC salga andando (despues de todo, estos son los info que mas se usan) para algun proximo release.

Viendo 8 entradas - de la 1 a la 8 (de un total de 8)
  • Debes estar registrado para responder a este debate.