Estamos creando una interfaz para ingresar documentos a trav茅s de la selecci贸n

imagen

En diversas aplicaciones comerciales, la tarea de entrada de documentos a menudo surge. Por lo general, un documento consta de un encabezado y algunas l铆neas, cada una de las cuales se refiere a alg煤n objeto (por ejemplo, producto). Con mayor frecuencia, se usa una tabla normal para ingresar registros en un documento, en el que el usuario puede agregar y eliminar filas, as铆 como cambiar su contenido.

Sin embargo, en algunos casos, este esquema no siempre es conveniente para los usuarios. En este art铆culo, le dir茅 c贸mo crear una interfaz de usuario conveniente utilizando la t茅cnica de selecci贸n de productos.

Desaf铆o


Como regla general, al ingresar documentos para el usuario, hay una restricci贸n en el conjunto de objetos que se le pueden agregar. En este caso, es l贸gico que el usuario muestre una lista de dichos objetos con la capacidad de incluirlos (y excluirlos) r谩pidamente en el documento. En las columnas, para cada uno de los objetos, tambi茅n es conveniente mostrar los datos necesarios para tomar una decisi贸n sobre la necesidad de incluirlos en el documento. Y finalmente, junto con el objeto, a menudo es necesario ingresar su cantidad.

Consideremos tres tipos de documentos que a menudo se encuentran en aplicaciones comerciales:

  1. Orden de compra En dichos documentos, es l贸gico que el usuario muestre una lista de todos los productos disponibles para ordenar al proveedor. En las columnas es conveniente mostrar el saldo actual, las ventas durante un cierto intervalo, la cantidad pedida para la compra y venta.
  2. Pedido de venta . Aqu铆, con mayor frecuencia, se muestra una lista de productos que se encuentran en el saldo del almac茅n seleccionado y disponibles para la venta al cliente seleccionado. Los precios actuales tambi茅n deben mostrarse.
  3. Cambio en saldos . Este documento se utiliza para ajustar los saldos actuales en caso de discrepancias con el monto real. Todos los productos generalmente se muestran en la selecci贸n, con la capacidad de ingresar el saldo real de cualquiera de ellos. Al mismo tiempo, se agrega un producto al documento con una cantidad igual a la diferencia entre el saldo actual y el actual.

Soluci贸n


A continuaci贸n, mostrar茅 c贸mo implementar r谩pida y f谩cilmente esta l贸gica basada en la plataforma lsFusion abierta y gratuita. Como ejemplo, creemos una l贸gica para ingresar una orden de compra.

Para comenzar, agregue una gu铆a de producto a trav茅s de la interfaz CRUD est谩ndar:
CLASS Product '' ;
name '' = DATA STRING [ 50 ] (Product);

FORM product ''
OBJECTS p = Product PANEL
PROPERTIES (p) name

EDIT Product OBJECT p //
;

FORM products ''
OBJECTS p = Product
PROPERTIES (p) READONLY name
PROPERTIES (p) NEWSESSION NEW , EDIT , DELETE

LIST Product OBJECT p // ,
;

NAVIGATOR {
NEW products;
}

Creamos el concepto de proveedor y, en forma de edici贸n, le damos la oportunidad de elegir los productos con los que trabaja:
CLASS Supplier '' ;
name '' = DATA STRING [ 50 ] (Supplier);

in '' = DATA BOOLEAN (Supplier, Product); // TRUE,

FORM supplier ''
OBJECTS s = Supplier PANEL
PROPERTIES (s) name

OBJECTS p = Product //
PROPERTIES in(s, p), name(p) READONLY //

EDIT Supplier OBJECT s
;

FORM suppliers ''
OBJECTS s = Supplier
PROPERTIES (s) READONLY name
PROPERTIES (s) NEWSESSION NEW , EDIT , DELETE

LIST Supplier OBJECT s
;

NAVIGATOR {
NEW suppliers;
}

Declare la l贸gica de orden con las l铆neas:
CLASS Order '' ;
date '' = DATA DATE (Order);
number '' = DATA INTEGER (Order);

supplier '' = DATA Supplier (Order);
nameSupplier '' (Order o) = name(supplier(o));

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail) NONULL DELETE ;

Agregue productos y cantidad a las l铆neas:
product '' = DATA Product (OrderDetail);
nameProduct '' (OrderDetail d) = name(product(d));

quantity '-' = DATA NUMERIC [ 14 , 3 ] (OrderDetail);

Procedemos directamente a la construcci贸n del formulario de edici贸n de pedidos que necesitamos. Primero, agregue el orden en s铆 y sus l铆neas:
FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number, nameSupplier

OBJECTS d = OrderDetail
PROPERTIES (d) nameProduct, quantity, NEW , DELETE
FILTERS order(d) = o

EDIT Order OBJECT o
;

Por lo tanto, obtenemos una interfaz est谩ndar para trabajar con l铆neas de pedido mediante la adici贸n y eliminaci贸n.
A continuaci贸n, agregamos la funcionalidad de selecci贸n que necesitamos a este formulario. Para hacer esto, primero cree un objeto en el formulario con una lista de todos los productos, en el que filtremos solo aquellos que pueden pedir al proveedor seleccionado:
EXTEND FORM order
OBJECTS p = Product
PROPERTIES name(p) READONLY
FILTERS in(supplier(o), p) //
;

Configuramos el dise帽o para que las l铆neas de pedido y la selecci贸n se muestren como pesta帽as de un contenedor:
DESIGN order {
OBJECTS {
NEW pane { //
fill = 1 ; //
type = TABBED ; // ,
MOVE BOX (d); //
MOVE BOX (p) { //
caption = '' ;
}
}
}
}

Construimos propiedades auxiliares para mostrar e ingresar la cantidad por el usuario en la columna correspondiente:
quantity '-' (Order o, Product p) =
GROUP SUM quantity(OrderDetail d) BY order(d), product(d);
lastOrderDetail ' ' (Order o, Product p) =
GROUP LAST OrderDetail d ORDER d BY order(d), product(d);

La primera propiedad considera la cantidad para este pedido y producto en este documento. El segundo encuentra la 煤ltima l铆nea (el usuario puede ingresar varias l铆neas con un producto).
A continuaci贸n, creamos una acci贸n que procesar谩 al usuario ingresando el valor en la columna correspondiente en la pesta帽a de selecci贸n:
changeQuantity ' -' (Order o, Product p) {
INPUT q = NUMERIC [ 14 , 3 ] DO { //
IF lastOrderDetail(o, p) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, p)
WHERE order(d) = o AND product(d) = p; //
ELSE // -
DELETE OrderDetail d WHERE order(d) = o AND product(d) == p;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
product(d) <- p;
quantity(d) <- q;
}
}
}

Finalmente, agregamos una columna al formulario, indicando la acci贸n que se debe realizar cuando el usuario intenta cambiar su valor:
EXTEND FORM order
PROPERTIES (o, p) quantity ON CHANGE changeQuantity(o, p)
;

Solo queda dibujar un formulario con una lista de pedidos y agregarlo al navegador:
FORM orders ''
OBJECTS o = Order
PROPERTIES (o) READONLY date, number
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

NAVIGATOR {
NEW orders;
}

La forma resultante se ver谩 as铆:

imagen

Cualquier cambio realizado en cualquiera de las pesta帽as se reflejar谩 autom谩ticamente en la otra.

En los sistemas ERP reales, se agregan significativamente m谩s columnas y otros elementos al formulario. Por ejemplo, en una de estas implementaciones, se ve as铆:

imagen


Veamos c贸mo se implementa esta funcionalidad en otras aplicaciones comerciales.

1C


En diferentes configuraciones de 1C, la l贸gica de selecci贸n tiene ciertas diferencias, pero el principio es m谩s o menos el mismo. Hay un bot贸n Seleccionar en el formulario de edici贸n de documentos, que muestra un cuadro de di谩logo con la elecci贸n de los productos:

imagen

En este cuadro de di谩logo, puede seleccionar los productos de la siguiente manera:

imagen

Hay al menos dos inconvenientes en este mecanismo.

En primer lugar, para agregar la cantidad del producto al documento (y la mayor铆a de las veces el usuario ya sabe la cantidad que desea agregar), primero debe hacer doble clic en el producto, agregarlo a las l铆neas y luego cambiar la cantidad en las l铆neas. Adem谩s, el usuario no ve en la lista de productos si este producto ya ha sido agregado y con qu茅 cantidad. Adem谩s, dicho esquema "come" espacio adicional, ya que debe mostrar dos tablas en una pantalla en lugar de una.

En segundo lugar, despu茅s de agregar las l铆neas directamente al documento, si vuelve a hacer clic en el bot贸n Seleccionar, la selecci贸n comenzar谩 "desde cero". No aparecer谩 ninguna fila en la tabla inferior, y en el momento de la re-selecci贸n no quedar谩 claro qu茅 ya est谩 en el documento y qu茅 no. Tambi茅n viola una de las reglas importantes al construir la interfaz: si el usuario se equivoca, entonces se le debe dar la oportunidad de volver y corregir el error. Aqu铆 resulta que no podr谩 volver a la selecci贸n de productos que tengan los mismos datos que antes de presionar el bot贸n Agregar al documento.

Sin embargo, es posible que en 1C pueda implementar el esquema anterior, pero por alguna raz贸n, en las configuraciones t铆picas que est谩n disponibles en el sitio con demostraciones, se usa otra.

Microsoft Dynamics 365


Como soluci贸n, tom茅 Retail (solo en 茅l encontr茅 una funcionalidad similar disponible en https://trials.dynamics.com ). En 茅l, puede llamar a la selecci贸n en el formulario 脫rdenes de compra de dos maneras:

imagen

El primer bot贸n se implementa de acuerdo con el esquema 1C (aunque hay muchas menos columnas), por lo que no me detendr茅 en 茅l.

El segundo bot贸n muestra un cuadro de di谩logo con una lista de productos donde la cantidad ya se puede ingresar en columnas. Pero esto se hace de una manera muy peculiar.

En primer lugar, de forma predeterminada, solo se muestran los c贸digos de producto all铆 (incluso sin nombres). Por supuesto, entiendo que puede crear extensiones e incluir otras columnas all铆, pero ver este comportamiento en la versi贸n b谩sica es un poco extra帽o.

En segundo lugar, Microsoft aparentemente se dej贸 llevar por el dise帽o que, por alguna raz贸n, obtuvieron puntajes en el procesamiento normal de datos de desplazamiento, trucos de procesamiento y eventos. Se parece a esto:

imagen

Durante el funcionamiento normal del teclado, las series actuales cambian constantemente cuando se vuelven a leer los datos. Al mismo tiempo, puede comenzar a ingresar solo despu茅s de esperar todo el procesamiento del evento; de lo contrario, la cantidad no se ingresa en absoluto o se ingresa en la serie incorrecta. C贸mo los usuarios reales trabajan con esto sigue siendo un misterio para m铆. Aparentemente, pocas personas usan esta funcionalidad espec铆ficamente. Bueno, o son las limitaciones de la demostraci贸n, pero en funcionamiento todo funciona bien.

Conclusi贸n


El esquema de entrada de documentos descrito a trav茅s de una pesta帽a de selecci贸n separada fue muy apreciado por nuestros usuarios.

En la pr谩ctica, este concepto puede ser complicado de varias maneras. Por ejemplo, en lugar de una lista de productos, muestre una lista de art铆culos con la capacidad de ingresar diferentes cantidades para caracter铆sticas individuales. O en uno de los documentos hab铆a almacenes en las filas, y se requer铆a establecer las cantidades para cada uno de estos almacenes en las columnas.

Tal esquema se puede implementar, por ejemplo, en el mismo React, usando las l铆neas actuales del documento como un estado y mostr谩ndolo con dos componentes en dos pesta帽as diferentes. Pero debe recordarse que puede haber muchas entradas en la tabla con productos, y tendr谩 que implementar el llamado "desplazamiento infinito". Adem谩s, es aconsejable agregar al usuario la capacidad de ordenar y filtrar productos en esta lista (y esto debe hacerse en el servidor y no en el cliente, para no arrastrar datos adicionales all铆). Todo esto se convierte en una tarea bastante trivial para el desarrollador.

En la plataforma lsFusion, esta funcionalidad se implementa de f谩brica y solo requiere el c贸digo descrito anteriormente. Puede probar c贸mo funciona y, si lo desea, puede modificar el c贸digo en l铆nea en la p谩gina correspondiente. Aqu铆 est谩 el c贸digo fuente completo, que se puede insertar en la pesta帽a Plataforma y luego haciendo clic en Reproducir:

C贸digo fuente
CLASS Product '' ;
name '' = DATA STRING [ 50 ] (Product);

FORM product ''
OBJECTS p = Product PANEL
PROPERTIES (p) name

EDIT Product OBJECT p //
;

FORM products ''
OBJECTS p = Product
PROPERTIES (p) READONLY name
PROPERTIES (p) NEWSESSION NEW , EDIT , DELETE

LIST Product OBJECT p // ,
;

NAVIGATOR {
NEW products;
}

CLASS Supplier '' ;
name '' = DATA STRING [ 50 ] (Supplier);

in '' = DATA BOOLEAN (Supplier, Product); // TRUE,

FORM supplier ''
OBJECTS s = Supplier PANEL
PROPERTIES (s) name

OBJECTS p = Product //
PROPERTIES in(s, p), name(p) READONLY //

EDIT Supplier OBJECT s
;

FORM suppliers ''
OBJECTS s = Supplier
PROPERTIES (s) READONLY name
PROPERTIES (s) NEWSESSION NEW , EDIT , DELETE

LIST Supplier OBJECT s
;

NAVIGATOR {
NEW suppliers;
}

CLASS Order '' ;
date '' = DATA DATE (Order);
number '' = DATA INTEGER (Order);

supplier '' = DATA Supplier (Order);
nameSupplier '' (Order o) = name(supplier(o));

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail) NONULL DELETE ;

product '' = DATA Product (OrderDetail);
nameProduct '' (OrderDetail d) = name(product(d));

quantity '-' = DATA NUMERIC [ 14 , 3 ] (OrderDetail);

FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number, nameSupplier

OBJECTS d = OrderDetail
PROPERTIES (d) nameProduct, quantity, NEW , DELETE
FILTERS order(d) = o

EDIT Order OBJECT o
;

EXTEND FORM order
OBJECTS p = Product
PROPERTIES name(p) READONLY
FILTERS in(supplier(o), p) //
;

DESIGN order {
OBJECTS {
NEW pane { //
fill = 1 ; //
type = TABBED ; // ,
MOVE BOX (d); //
MOVE BOX (p) { //
caption = '' ;
}
}
}
}

quantity '-' (Order o, Product p) =
GROUP SUM quantity(OrderDetail d) BY order(d), product(d);
lastOrderDetail ' ' (Order o, Product p) =
GROUP LAST OrderDetail d ORDER d BY order(d), product(d);

changeQuantity ' -' (Order o, Product p) {
INPUT q = NUMERIC [ 14 , 3 ] DO { //
IF lastOrderDetail(o, p) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, p)
WHERE order(d) = o AND product(d) = p; //
ELSE // -
DELETE OrderDetail d WHERE order(d) = o AND product(d) == p;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
product(d) <- p;
quantity(d) <- q;
}
}
}

EXTEND FORM order
PROPERTIES (o, p) quantity ON CHANGE changeQuantity(o, p)
;

FORM orders ''
OBJECTS o = Order
PROPERTIES (o) READONLY date, number
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

NAVIGATOR {
NEW orders;
}

Source: https://habr.com/ru/post/464487/


All Articles