Il s'avère que le cliché "plus on est defous, plus on rit" n'est pas toujours vrai - ni approprié d'ailleurs. Par exemple, en ce qui concerne le trafic, les hypothèques, les "influenceurs" d'IG et... le nombre de clics de souris nécessaires pour réaliser une activité dans un système logiciel, plus n'est certainement pas mieux.
Lorsque les systèmes sont déployés dans de grands entrepôts très fréquentés, les utilisateurs préfèrent souvent passer directement de l'écran Acumatica à l'imprimante en un seul clic. Dans Acumatica, par défaut, ce processus nécessite au moins quelques clics supplémentaires et quelques secondes d'attente pendant le chargement de la fenêtre de prévisualisation avant que le document ne soit réellement imprimé.
À partir de la version 2018 R1, Acumatica a inclus la fonctionnalité Device Hub qui est un processus fonctionnant constamment en arrière-plan, interrogeant les nouveaux documents à imprimer, afin qu'ils puissent passer d'Acumatica à la file d'attente de l'imprimante en un seul clic.
Dans cet article de blog, nous allons passer en revue le processus nécessaire pour y parvenir en examinant l'installation, la configuration et quelques bons vieux exemples de code.
Installation du concentrateur de périphériques d'impression
Lorsque l'assistant de configuration d'Acumatica ERP est lancé au cours du processus d'installation, l'une des fonctions de configuration disponibles est Install DeviceHub. Assurez-vous que cette case est cochée et poursuivez ensuite le reste de l'installation comme il se doit.
Configuration de l'imprimante dans le serveur
Étant donné que toute cette configuration est effectuée sur un nouveau serveur, nous devons nous assurer qu'au moins une imprimante est correctement configurée et opérationnelle. Dans ce cas, nous utiliserons l'imprimante Microsoft Printer to PDF (redirected 2 ).
Nous vérifions qu'un document test est correctement ajouté à la file d'attente de l'imprimante :
Configuration de l'environnement
Dans la page Enable/Disable Features (CS100000), assurez-vous que l'option DeviceHub est sélectionnée :
L'application DeviceHub elle-même comporte deux onglets à configurer : le site et les imprimantes.
Veuillez noter que le DeviceHub étant un processus exécuté en permanence en arrière-plan pour demander au système s'il y a de nouvelles informations à ajouter à la file d'attente de l'imprimante, il est pratique de créer un utilisateur spécifique à cette fin.
Après avoir appuyé sur OK, le DeviceHub commence à fonctionner et à interroger les nouveaux documents à imprimer.
Notez également que si la fenêtre DeviceHub est fermée, le processus continuera à s'exécuter en arrière-plan. Pour l'arrêter, il convient d'utiliser le gestionnaire de tâches.
Configuration Acumatica
La première chose à faire est de rendre l'imprimante disponible dans Acumatica. Cela se fait à partir de la page Imprimantes (SM206510).
Dans cette page, le bouton Mettre à jour la liste des imprimantes est utilisé pour remplir la grille avec les imprimantes précédemment définies dans le DeviceHub.
Si aucun résultat n'est visible dans la grille après avoir appuyé sur le bouton " Mettre à jour la liste des imprimantes ", le bouton "Annuler" doit être utilisé pour rafraîchir la grille.
Cette opération met à jour la liste des imprimantes disponibles dans le DeviceHub.
Les imprimantes étant déjà disponibles dans Acumatica, l'étape suivante consiste à affecter les différents utilisateurs aux différentes imprimantes. Par exemple, cela permettra à l'équipe administrative d'utiliser une imprimante, et à l'équipe des préparateurs de commandes de l'entrepôt d'utiliser une autre imprimante séparée dans un endroit différent. Cette opération s'effectue dans la page d'accès à l'imprimante (SM106000).
Cette page est composée de deux onglets : les utilisateurs et les imprimantes associées.
Notez que les utilisateurs sélectionnés dans le groupe ne nécessitent pas l'inclusion de l'utilisateur DeviceHub précédemment créé, car ils ont des objectifs différents : le premier est utilisé pour identifier l'imprimante à utiliser et le second est utilisé pour interroger les travaux dans la file d'attente.
Notez également que les imprimantes et les utilisateurs peuvent appartenir à plusieurs groupes. L'effet de cette configuration est visible dans le champ GroupMask de la table RelationGroup, où une combinaison de valeurs binaires permet au système d'identifier correctement l'imprimante à utiliser.
Une fois tous les réglages et configurations terminés, nous allons étendre la page Inventaire et ajouter un nouveau bouton permettant d'imprimer un rapport :
Étape 1 - Un graphique est créé pour gérer la logique d'impression :
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
}
}
Étape 2 - Logique étendue pour ajouter le bouton d'impression
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();
}
}
}
Exemple de résultat
Lorsque l'utilisateur appuie sur le nouveau bouton Imprimer le solde de l'élément, le rapport est ajouté directement dans la file d'attente de l'imprimante :
Et le DeviceHub indique le travail en cours d'impression :
La liste des demandes d'impression en attente et traitées se trouve dans la page Travaux d'impression:
Conclusion
Tirez parti de la fonction Device Hub dans Acumatica R1 et les versions ultérieures. L'impression de quelques documents par jour à l'aide de cette fonctionnalité n'a pas d'effet significatif dans de nombreux cas. Cependant, pour les entrepôts en pleine effervescence où de nouvelles palettes, boîtes et paquets sont continuellement assemblés, les quelques secondes gagnées, par demande d'impression, s'additionnent à la fin de la journée. Cela se traduit directement par une augmentation de l'efficacité et des performances. Car vous savez ce que l'on dit : "le temps, c'est de l'argent".
*Cliquez sur le lien pour télécharger l'exemple de code C# de l'article.