Configuración del concentrador de dispositivos

Fernando Amadoz | 25 de marzo de 2022

Resulta que el tópico "cuantomás, mejor" no siempre es cierto, ni apropiado. Por ejemplo, en lo que respecta al tráfico, las hipotecas, los "influencers" de IG y... el número de clics de ratón necesarios para completar una actividad en un sistema de software, más no es mejor.

Cuando los sistemas se implantan en almacenes grandes y con mucho movimiento, a menudo la preferencia de los usuarios es pasar directamente de la pantalla de Acumatica a la impresora en un solo clic. En Acumatica, por defecto, este proceso requiere al menos un par de clics adicionales y unos segundos de espera mientras se carga la ventana de vista previa antes de que el documento se imprima realmente.

Configuración del concentrador de dispositivos

A partir de la versión 2018 R1, Acumatica incluyó la función Device Hub, que es un proceso que se ejecuta constantemente en segundo plano sondeando los nuevos documentos que se van a imprimir, para que puedan pasar de Acumatica a la cola de impresión en un solo clic.

En esta entrada del blog revisaremos el proceso necesario para que esto suceda mediante la revisión de la instalación, configuración y algunos buenos ejemplos de código antiguo.

Instalación del concentrador de dispositivos de impresión

Cuando se ejecuta el asistente de configuración de Acumatica ERP durante el proceso de instalación, una de las funciones de configuración disponibles es Instalar DeviceHub. Asegúrate de que esta casilla de verificación esté seleccionada y luego continúa con el resto de la instalación como se haría normalmente.

Instalar DeviceHub

Configuración de la impresora en el servidor

Dado que toda esta configuración se está realizando en un servidor nuevo, necesitamos asegurarnos de que al menos una impresora está correctamente configurada y operativa. En este caso, utilizaremos la impresora Microsoft Printer to PDF (redirigida 2)

Configuración de la impresora en el servidor

Verificamos que un documento de prueba se añade correctamente a la cola de impresión:

Verificar que un documento de prueba se añade correctamente a la cola de impresión

Configuración del entorno

En la página Activar/Desactivar funciones (CS100000), asegúrese de que la opción DeviceHub está seleccionada:

Configuración del entorno

La propia aplicación DeviceHub tiene 2 pestañas para configurar: el sitio y las impresoras.

Configuración de DeviceHub
Configuración de DeviceHub

Tenga en cuenta que debido a que el DeviceHub es un proceso que se ejecuta continuamente en segundo plano preguntando al sistema si hay nueva información que añadir a la cola de impresión, es conveniente tener un usuario específico creado para este fin.

Tras pulsar OK, el DeviceHub empezará a funcionar y a sondear nuevos documentos para imprimir.

DeviceHub se está ejecutando y sondeo de nuevos documentos a imprimir

Ten en cuenta también que si se cierra la ventana de DeviceHub, el proceso seguirá ejecutándose en segundo plano. Para detenerlo, se debe utilizar el administrador de tareas.

Estado del DeviceHub

Configuración de Acumatica

Lo primero que debe hacerse es hacer que la impresora esté disponible en Acumatica. Esto se logra desde la página Impresoras (SM206510).

En esta página, el botón Actualizar lista de impresoras se utiliza para rellenar la cuadrícula con las impresoras previamente definidas en el DeviceHub.

Configuración de Acumatica

De nuevo, observe que si no hay resultados visibles en la cuadrícula después de pulsar el botón Actualizar lista de impresoras, deberá utilizar el botón Cancelar para actualizar la cuadrícula.

Al hacerlo, se actualizará la lista de impresoras disponibles en el DeviceHub.

Lista de impresoras disponibles en el DeviceHub

Teniendo las impresoras ya disponibles en Acumatica, el siguiente paso es asignar los diferentes usuarios a diferentes impresoras. Por ejemplo, esto permitirá que el equipo administrativo utilice una impresora y que el equipo de recolectores del almacén utilice otra impresora separada en una ubicación diferente. Esto se hace en la página Acceso a impresoras (SM106000).

Esta página consta de dos pestañas: los usuarios y las impresoras asociadas.

Los usuarios y las impresoras asociadas

Tenga en cuenta que los usuarios seleccionados en el grupo no requieren la inclusión del usuario DeviceHub creado previamente, ya que tienen propósitos diferentes: el primero se utiliza para identificar la impresora que se va a utilizar y el segundo se utiliza para el sondeo de trabajos en la cola.

Observe también que las impresoras y los usuarios pueden pertenecer a varios grupos. El efecto de esta configuración es visible en el campo GroupMask de la tabla RelationGroup, donde una combinación de valores binarios permite al sistema identificar correctamente qué impresora utilizar.

Con todos los ajustes y configuraciones completados, a continuación ampliaremos la página de Inventario y se añadirá un nuevo botón para imprimir un informe:

Paso 1 - Se crea un gráfico para gestionar la lógica de impresión:


using System;
using System.Collections.Generic;
using PX.SM;
using PX.Data;
using PX.Objects.CS;
using PX.Objects.IN;
using PX.Objects.CR;
using PX.Objects.AR;

namespace AcumaticaDeviceHub
{
    public class PEPrintSLMaint : PXGraph<PEPrintSLMaint>
    {
        #region DAC PrintParameters
        [System.SerializableAttribute]
        public partial class PrintParameters : IBqlTable, PX.SM.IPrintable
        {
            #region PrintWithDeviceHub
            public abstract class printWithDeviceHub : IBqlField
            {
            }
            [PXDBBool]
            [PXDefault(typeof(FeatureInstalled<FeaturesSet.deviceHub>))]
            [PXUIField(DisplayName = "Print with DeviceHub")]
            public virtual bool? PrintWithDeviceHub { get; set; }
            #endregion
            #region DefinePrinterManually
            public abstract class definePrinterManually : IBqlField
            {
            }
            [PXDBBool]
            [PXDefault(true)]
            [PXUIField(DisplayName = "Define Printer Manually")]
            public virtual bool? DefinePrinterManually { get; set; }
            #endregion
            #region Printer
            public abstract class printerName : PX.Data.IBqlField { }
            [PX.SM.PXPrinterSelector]
            public virtual string PrinterName { get; set; }
            #endregion
        }
        #endregion

        public static class Parameters
        {
            public const string Inventory_ID = "Inventory_ID";
        }

        public static class Fields
        {
            public static readonly string Inventory_ID = string.Format("{0}.{1}", nameof(InventoryItem), nameof(Parameters.Inventory_ID));
        }

        #region Methods
        public void PrintReportInDeviceHub(string reportID, string actualReportID, List<string> nameGroupsList, Dictionary<string, string> parametersDictionary, string printerName, int numberPrint)
        {
            Guid loggedUser = this.Accessinfo.UserID;

            Users usersRow = PXSelect<Users,
                                    Where<Users.pKID, Equal<Required<Users.pKID>>>>
                                    .Select(this, loggedUser);
            string BinaryGroupMask = Convert.ToString(usersRow.GroupMask[0], 2);

            List<string> ListGroupsUser = new List<string>();
            for (int i = 0; i < BinaryGroupMask.Length; i++)
            {
                if (BinaryGroupMask.Substring(i, 1) != "0")
                {
                    String BinaryGroup = (BinaryGroupMask.Substring(i, 1).PadLeft(i + 1, '0')).PadRight(BinaryGroupMask.Length, '0');
                    ListGroupsUser.Add(Convert.ToString(Convert.ToDecimal(Convert.ToByte(BinaryGroup, 2))));
                }

            }

            Dictionary<string, string> groupsUserDictionary = new Dictionary<string, string>();
            foreach (String GroupUser in ListGroupsUser)
            {
                foreach (RelationGroup relationGroupRow in PXSelect<RelationGroup, Where<RelationGroup.active, Equal<Required<RelationGroup.active>>>>.Select(this, 1))
                {
                    if (Convert.ToString(relationGroupRow.GroupMask[0]) == GroupUser)
                    {
                        groupsUserDictionary[relationGroupRow.GroupName] = Convert.ToString(relationGroupRow.GroupMask[0]);
                        break;
                    }
                }
            }

            foreach (SMPrinter printersRow in PXSelect<SMPrinter, Where<SMPrinter.isActive, Equal<Required<SMPrinter.isActive>>>>.Select(this, 1))
            {
                foreach (string nameGroup in nameGroupsList)
                {
                    if (groupsUserDictionary.ContainsKey(nameGroup))
                    {
                        if (groupsUserDictionary[nameGroup] == Convert.ToString(printersRow.GroupMask[0]))
                        {
                            printerName = printersRow.PrinterName;
                            break;
                        }
                    }
                }
            }

            if (String.IsNullOrEmpty(printerName))
            {
                throw new PXException(Convert.ToString("The user is not active in an impression group"));
            }

            Dictionary<string, PXReportRequiredException> reportsToPrint = new Dictionary<string, PXReportRequiredException>();
            PrintParameters filter = new PrintParameters();
            filter.PrintWithDeviceHub = true;
            filter.DefinePrinterManually = true;
            filter.PrinterName = printerName;

            for (int i = 0; i < numberPrint; i++)
            {
                reportsToPrint = PX.SM.SMPrintJobMaint.AssignPrintJobToPrinter(reportsToPrint, parametersDictionary, filter,
                new NotificationUtility(this).SearchPrinter, ARNotificationSource.Customer, reportID, actualReportID, 16);
            }

            if (reportsToPrint != null)
            {
                PX.SM.SMPrintJobMaint.CreatePrintJobGroups(reportsToPrint);
            }
        }
        #endregion
    }
}

Paso 2 - Lógica extendida para añadir el botón de impresión


using System.Collections;
using System.Collections.Generic;
using PX.Data;
using PX.Objects.IN;

namespace AcumaticaDeviceHub
{
    public class InventoryItemMaintSKExt : PXGraphExtension<InventoryItemMaint>
    {
        public PXAction<InventoryItem> printLabel;
        [PXUIField(DisplayName = "Print Item Balance", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
        [PXButton(CommitChanges = true)]
        public virtual IEnumerable PrintLabel(PXAdapter adapter)
        {
            PEPrintSLMaint tGPrintGraph = PXGraph.CreateInstance<PEPrintSLMaint>();

            Dictionary<string, string> parametersDictionary = new Dictionary<string, string>();
            parametersDictionary[PEPrintSLMaint.Fields.Inventory_ID] = this.Base.Item.Current.InventoryCD.Trim();
            List<string> ListGroupsFilter = new List<string> { "Group1", "Group2", "Group3" };
            tGPrintGraph.PrintReportInDeviceHub("IN615000", "IN615000", ListGroupsFilter, parametersDictionary, null, 1);

            return adapter.Get();
        }
    }
}

Ejemplo Resultado

Saldo de la partida de impresión

Cuando el usuario pulsa sobre el nuevo botón Imprimir saldo de elementos, el informe se añade directamente en la cola de impresión:

Cola de impresión

Y el DeviceHub indica el trabajo que se está imprimiendo:

DeviceHub indica el trabajo que se está imprimiendo

La lista de las solicitudes de impresión pendientes y procesadas se encuentra en la página Trabajos de impresión:

Imprimir página de trabajos

Conclusión

Aproveche la función Device Hub de Acumatica R1 y versiones posteriores. Imprimir unos pocos documentos al día con esta función no tiene un efecto significativo en muchos casos. Sin embargo, para los almacenes bulliciosos en los que se montan continuamente nuevos palés, cajas y paquetes, unos pocos segundos ahorrados, por solicitud de impresión, suman al final del día. Esto se traduce directamente en una mayor eficiencia y rendimiento. Porque ya sabe lo que dicen: "el tiempo es oro".


*Haga clic en el enlace para descargar el código de ejemplo C# del artículo.

 

 

Entradas relacionadas

Autor del blog

Fundador y CEO de SkyKnack, un proveedor de soluciones ERP que ayuda a los socios de Acumatica a desarrollar personalizaciones, integraciones y nuevos productos, así como servicios de implementación y formación.

Reciba las actualizaciones del blog en su bandeja de entrada.