Inicio Blog Plugin de personalización de Acumatica: Cómo añadir o cambiar la configuración de un paquete

Plugin de personalización de Acumatica: Cómo añadir o cambiar la configuración de un paquete

Vinay Koppula | 13 de octubre de 2022

Plugin de personalización de Acumatica: Cómo añadir o cambiar la configuración de un paquete

Introducción

He trabajado en un buen número de soluciones de integración ISV, y cada vez, las pruebas unitarias en las nuevas instancias significan que debo introducir o actualizar los ajustes necesarios de las integraciones. Estas entradas pueden ser muy molestas y llevar mucho tiempo. También me he dado cuenta de que la mayoría de las integraciones requieren preconfiguraciones o ajustes, como la configuración de la integración, la clase de cliente, los tipos de pedido, los valores predeterminados, la secuencia de numeración predeterminada, etc. Cada vez que se implementa una solución ISV, habrá una buena cantidad de esfuerzo manual para establecer las configuraciones iniciales.

Mientras buscaba la solución, encontré un artículo de Sergey Marenich sobre Site Configuration using Customization (Configuración del sitio mediante personalización ), que explica cómo podemos añadir (o cambiar) la configuración de paquetes en Acumatica ERP directamente desde el complemento de personalización. Este artículo me ayudó a entender y trabajar en mi requisito.

El complemento personalizado es un archivo de código independiente

Lo que he aprendido es que Customization Plug-In es un archivo de código separado con una clase que Acumatica puede compilar y cargar dinámicamente durante la publicación.

Los eventos de clase se suscriben automáticamente y se ejecutan en operaciones de Base de Datos y/o Archivos.

Los dos eventos de clase son:

  • OnPublished - aquí puede acceder al sistema de archivos y realizar la configuración adecuada antes de que se reinicie la aplicación.
  • UpdateDatabase - aquí puede tener algunas operaciones que deben ser ejecutadas para asegurar sus propios scripts de actualización de base de datos.

Este es el fragmento de código de ejemplo (Proyecto de ejemplo disponible en GitHub):

//Customization plugin is used to execute custom actions after customization project was published
public class MyPlugIn : CustomizationPlugin
{
//This method executed right after website files were updated, but before website was restarted
//Method invoked on each cluster node in cluster environment
//Method invoked only if runtimecompilation is enabled
//Do not access custom code published to bin folder, it may not be loaded yet
public override void OnPublished()
{
this.WriteLog("OnPublished Event");
}
//This method executed after customization was published and website was restarted.
public override void UpdateDatabase()
{
this.WriteLog("UpdateDatabase Event");
}
}

GitHub: https://github.com/vinayrajk/CustomizationPlugin>

A continuación se muestra el archivo de clase extraído del código del proyecto de ejemplo de GitHub.

using System;
using PX.Data;
using Customization;
using PX.Objects.SO;
using PX.Objects.CS;
namespace Integration
{
//Customization plugin is used to execute custom actions after customization project was published
public class MyPlugIn : CustomizationPlugin
{
//This method executed right after website files were updated, but before website was restarted
//Method invoked on each cluster node in cluster environment
//Method invoked only if runtimecompilation is enabled
//Do not access custom code published to bin folder, it may not be loaded yet
public override void OnPublished()
{
WriteLog("OnPublished Event");
}
//This method executed after customization was published and website was restarted.
public override void UpdateDatabase()
{
#region Numbering sequence
NumberingMaint graph = PXGraph.CreateInstance<NumberingMaint>();
string newNumbering = EBConstants.serviceRepairOrderType;
Numbering numbering1 = PXSelect<Numbering, Where<Numbering.numberingID, Equal<Required<Numbering.numberingID>>>>.Select(graph, "EBOrders");
if (numbering1 == null)
{
var numbering = graph.Header.Insert();
numbering.NumberingID =EBConstants.NumberingID;
numbering.Descr =EBConstants.Descr;
numbering.NewSymbol = EBConstants.NewSymbol;
var soNumbering = graph.Sequence.Insert();
soNumbering.StartNbr = EBConstants.StartNbr;
soNumbering.EndNbr = EBConstants.EndNbr;
soNumbering.StartDate = Convert.ToDateTime(Convert.ToDateTime(graph.Accessinfo.BusinessDate).ToShortDateString());
soNumbering.LastNbr = EBConstants.LastNbr;
soNumbering.WarnNbr =EBConstants.WarnNbr;
soNumbering.NbrStep =EBConstants.NbrStep;
graph.Persist();
WriteLog(string.Format("{0} Numbering sequence has been added", newNumbering));
}
else
WriteLog(string.Format("{0} Numbering sequence already created", newNumbering));
#endregion
#region OrderType
SOOrderTypeMaint otgraph = PXGraph.CreateInstance<SOOrderTypeMaint>();
string newOrderTypeName = EBConstants.serviceRepairOrderType;
SOOrderType sOOrderType = PXSelect<SOOrderType, Where<SOOrderType.orderType, Equal<Required<SOOrderType.orderType>>>>.Select(otgraph, "EB");
if (sOOrderType == null)
{
//Assigning default values to the OrderType Obeject
//Here you can assign the required values that you would like to create the ordertype based on the requirement during the package publish process
var soSRTypeGeneral = otgraph.soordertype.Insert();
soSRTypeGeneral.OrderType = EBConstants.OrderType;
soSRTypeGeneral.Descr = EBConstants.Descr;
soSRTypeGeneral.Template =EBConstants.Template;
soSRTypeGeneral.Active = EBConstants.Active;
soSRTypeGeneral.OrderNumberingID = EBConstants.OrderNumberingID;
soSRTypeGeneral.DaysToKeep =EBConstants.DaysToKeep;
soSRTypeGeneral.CalculateFreight = EBConstants.CalculateFreight;
soSRTypeGeneral.SupportsApproval = EBConstants.SupportsApproval;
soSRTypeGeneral.InvoiceNumberingID = EBConstants.InvoiceNumberingID;
soSRTypeGeneral.SalesAcctDefault = EBConstants.SalesAcctDefault;
soSRTypeGeneral.SalesSubMask = EBConstants.SalesSubMask;
soSRTypeGeneral.FreightAcctID = EBConstants.FreightAcctID;
soSRTypeGeneral.FreightAcctDefault =EBConstants.FreightAcctDefault;
soSRTypeGeneral.FreightSubID = EBConstants.FreightSubID;
soSRTypeGeneral.FreightSubMask = EBConstants.FreightSubMask;
soSRTypeGeneral.DiscountAcctID = EBConstants.DiscountAcctID;
soSRTypeGeneral.DiscAcctDefault =EBConstants.DiscAcctDefault;
soSRTypeGeneral.DiscountSubID = EBConstants.DiscountSubID;
soSRTypeGeneral.DiscSubMask =EBConstants.DiscSubMask;
soSRTypeGeneral.Behavior = EBConstants.Behavior;
soSRTypeGeneral.DefaultOperation = EBConstants.DefaultOperation;
soSRTypeGeneral.ARDocType = EBConstants.ARDocType;
soSRTypeGeneral.AllowQuickProcess = EBConstants.AllowQuickProcess;
soSRTypeGeneral.RequireShipping = EBConstants.RequireShipping;
soSRTypeGeneral.INDocType = EBConstants.INDocType;
var soSRTypeTemplate = otgraph.operations.Insert();
soSRTypeTemplate.OrderType = EBConstants.OrderType;
soSRTypeTemplate.Active = EBConstants.Active;
soSRTypeTemplate.InvtMult = EBConstants.InvtMult;
soSRTypeTemplate.Operation = EBConstants.Operation;
soSRTypeTemplate.INDocType = EBConstants.INDocType;
soSRTypeTemplate.OrderPlanType = EBConstants.OrderPlanType;
soSRTypeTemplate.ShipmentPlanType = EBConstants.ShipmentPlanType;
otgraph.operations.Cache.Update(soSRTypeTemplate);
var soSRTypeQuickParam = otgraph.quickProcessPreset.Insert();
soSRTypeQuickParam.OrderType = EBConstants.OrderType;
soSRTypeQuickParam.UpdateIN = EBConstants.UpdateIN;
soSRTypeQuickParam.CreateShipment = EBConstants.CreateShipment;
soSRTypeQuickParam.PrepareInvoice = EBConstants.PrepareInvoice;
soSRTypeQuickParam.ConfirmShipment = EBConstants.ConfirmShipment;
otgraph.quickProcessPreset.Cache.Update(soSRTypeQuickParam);
otgraph.Persist();
WriteLog(string.Format("{0} Order type has been added", newOrderTypeName));
}
else
WriteLog(string.Format("{0} Order type already created", newOrderTypeName));
#endregion
#region Integration Setup
IntegrationSetupMaint setupgraph = PXGraph.CreateInstance<IntegrationSetupMaint>();
string integrationsetupgraph = EBConstants.serviceRepairOrderType;
IntegrationSetup integrationSetup = PXSelect<IntegrationSetup, Where<IntegrationSetup.integrationID, Equal<Required<IntegrationSetup.integrationID>>>>.Select(setupgraph, "EBay Orders");
if (integrationSetup == null)
{
var sointegration = setupgraph.IntegrationSetup.Insert();
sointegration.IntegrationID = EBConstants.IntegrationID;
sointegration.OrderType = EBConstants.OrderType;
setupgraph.Persist();
WriteLog(string.Format("{0} eBay Integration ID has been added", integrationsetupgraph));
}
else
WriteLog(string.Format("{0} eBay Integration ID already created", integrationsetupgraph));
#endregion
}
}
}
view raw MyPlugIn.cs hosted with ❤ by GitHub

Ajustes más comunes de los plugins

A continuación se muestran los ajustes más comunes que he utilizado en la pantalla de Configuración de la integración.

  • Default Customer-Esto se puede utilizar en la integración de marketplace si los pedidos son de Fulfilment by marketplaces.
  • Clase de cliente-Se puede definir si las integraciones tienen un ajuste para seleccionar la clase de cliente.
  • Secuencia de numeración -Establezca la secuencia de numeración por defecto, que puede cambiar posteriormente.
  • Tipos de Pedidos-Si los pedidos se van a identificar por separado, entonces se puede establecer un valor por defecto en la pantalla de configuración, por ejemplo, para cualquier integración de mercado como eBay, Amazon, Walmart, etc. Se puede crear un tipo de Orden base como EB o WM, y su valor puede ser llenado en las pantallas de configuración.
  • Cualquier valor por defecto para cualquier pantalla de configuración.

La configuración anterior se puede crear o actualizar en cuanto el paquete se despliega en la instancia con un evento UpdateDatabase.

Nota: Debemos ser cautelosos con los datos actualizados, y no debe afectar a ninguna otra parte de los datos sensibles. 

El proyecto de ejemplo está disponible en el GitHub, por favor siga https://github.com/vinayrajk/CustomizationPlugin.git

Resumen:

Esperamos que este artículo le ayude a comprender el uso del plugin de personalización y a conectar y utilizar las soluciones ISV con la configuración predeterminada que viene con el paquete.

¡Feliz codificación!

Autor del blog

Durante los últimos doce años, Vinay ha desarrollado soluciones empresariales utilizando el marco .NET y se trasladó a Kensium, donde ha pasado siete años perfeccionando sus habilidades en Acumatica. Ha pasado de desarrollador a director de desarrollo, creando soluciones complejas y personalizaciones en Acumatica. Ha completado proyectos como IBS Imperium, una solución OEM para la gestión inmobiliaria, integraciones de tiendas como pagos, extensiones de impuestos e integraciones de mercados. En su papel de director de desarrollo, contribuye a la formación y tutoría de nuevos desarrolladores, ayudándoles a alcanzar sus objetivos profesionales.

Reciba las actualizaciones del blog en su bandeja de entrada.