CAPÍTULO VIII Desarrollo de Plug-In
CAPÍTULO VIII Desarrollo de Plug-In
CAPÍTULO VIII Desarrollo de Plug-In
Desarrollo de Plug-in
Ejemplos:
Ejemplo del Plugin completo en idempiere-plugin-template
Ejemplo del Plugin de iDempiere
idempiere-plugin-template/com.ingeint.template
Ejemplo del Plugin de iDempiere Unit Test
idempiere-plugin-template/com.ingeint.template.test
Ejemplo del Plugin de iDempiere Target Platform
idempiere-plugin-template/com.ingeint.template.targetplatform
Pre-requisitos
Java 11, comandos java y javac
Establecer variable de entorno IDEMPIERE_REPOSITORY
Comandos de uso
Comando Descripción
Componentes
El plugin tendrá tres componentes:
● El nuevo plugin de idempiere.
● Fragmento de prueba unitaria iDempiere.
● Plataforma de destino iDempiere.
Comandos
Compilar plugin y ejecutar pruebas:
./build
Flujo de Trabajo
Usando Java
Esta forma es algo anticuado y más incómodo que los otros
enfoques, pero por motivos de exhaustividad, se les mostrará. En primer
lugar se crea otra clase llamada JavaCallout, la cual hereda de
"CalloutEngine" y se crea un nuevo método siguiendo la siguiente
estructura:
El flujo de trabajo
X_, I_, M? ¿Qué clase es para qué?
En iDempiere tenemos diferentes clases para nuestros modelos. La clase
toplevel se llama PO, que significa Objeto persistente. Cada modelo hereda
sus métodos. Si generas modelos o echas un vistazo a los existentes, verás
que la mayoría de las tablas tienen una X_ y I_ clase.
IModelFactory
Nota : si utiliza Eclipse Oxigen o una versión más reciente, puede
utilizar anotaciones en lugar de crear la definición de componente
manualmente.
● Un modelo
● Un ModelFactory (que es solo una clase que implementa
IModelFactory)
Básicamente, eso es todo lo que necesitas hacer. Para ver que realmente
hicimos algo, abra de nuevo la clase de modelo personalizado y agregue un
inicio de sesión de consola beforeSave()
Asegúrese de que el complemento está activo en las configuraciones de
ejecución.
Ahora inicie sesión y cree un nuevo pedido de ventas complete todos los
campos obligatorios y haga clic en guardar. Eche un vistazo al registro de la
consola, debería ver el registro de la clase de modelo personalizado:
4. Proceso.
El objetivo es mostrar cómo desarrollaría un nuevo proceso dentro de un
complemento. También descubriremos información útil sobre cómo utilizar
los procesos de iDempiere correctamente.
Lo que aprenderás:
Flujo de Trabajo
Uso de puntos de extensión
<extension
id="org.notima.idempiere.process.CreateWarehouseLocators"
name="org.notima.idempiere.process.CreateWarehouseLocators"
point="org.adempiere.base.Process">
<process
class="org.notima.idempiere.process.CreateWarehouseLocators">
</process>
</extension>
</plugin>
Inicie sesión como Sistema. Abra la ventana Informe y proceso, cree una nueva
entrada. Lo llamamos MyProcess. Como nombre de clase, inserte el nombre de
clase completo (en nuestro caso org.evenos.process.MyProcess):
Cambie a la pestaña Parámetro y agregue algunos parámetros. Para fines de
prueba, agregaremos los siguientes parámetros: -M_Product_ID - Table Direct -
DBColumn "M_Product_ID" -SomeString - String - DBColumn "SomeString"
-SomeInteger - Integer - DBColumn "SomeInteger"
Abra la ventana Menú y cree una nueva entrada. Asígnele el nombre MyProcess y
elija Process como acción. En el campo Proceso, seleccione el proceso creado
anteriormente:
Cierre la sesión y vuelva a entrar. Debería ver su Proceso en el menú. Si ha hecho
todo bien, puede iniciarlo y devolverá "** null" como mensaje. Si se produce algún
error, asegúrese de seguir nuestros tutoriales anteriores. Compruebe si el
complemento está iniciado y activo y si ha elegido los nombres de clase correctos.
Dale un nombre único y haz clic en finalizar. Una vez creado, asegúrese de que se
crea la entrada correspondiente en su MANIFIESTO. Archivo MF. Me gusta poner
todas mis definiciones de componentes en una carpeta llamada OSGI-INF y solo
agregar esta carpeta a mi manifiesto:
Export-Package: ...
Service-Component: OSGI-INF/*.xml
Bundle-ClassPath: ...
Bundle-Activator: ...
Parámetros de lectura
Regrese a Eclipse y abra MyProcess, es hora de agregar más funcionalidad aquí.
Primero queremos leer los parámetros para este proceso. Comience agregando
las variables de instancia. Luego vaya a prepare() y agregue el código para leer en
los parámetros. Ahora debería verse así (excepto el error tipográfico en
M_Product_ID ;):
addLog(getProcessInfo().getAD_Process_ID(),
new Timestamp(System.currentTimeMillis()),
new BigDecimal(getProcessInfo().getAD_PInstance_ID()),
"The input string was: " + someString);
addLog(getProcessInfo().getAD_Process_ID(),
new Timestamp(System.currentTimeMillis()),
new BigDecimal(getProcessInfo().getAD_PInstance_ID()),
"The input integer was: " + someInteger,
MProduct.Table_ID,
m_product_id);
Hay más que puede y debe registrar. ¿Ha notado que doIt() puede lanzar
excepciones y devolver un String? La instrucción return se muestra al usuario.
¿Recuerdas el mensaje "** null" cuando iniciamos el proceso? Puedes decidir lo
que quieres devolver. Si desea lanzar un error, puede hacerlo. El proceso en
ejecución actual se detendrá y mostrará la descripción del error localizado en lugar
de la declaración de retorno. Si marca la ventana Auditoría de procesos, puede ver
si un proceso se canceló debido a un error por su valor de resultado. 0 significa
que se produjo una excepción, 1 significa que devolvió su propio valor.
Agreguemos una instrucción para que sea posible lanzar errores:
Inicie el cliente iDempiere y pruebe el nuevo proceso. Inicie sesión para que tenga
algunos productos disponibles. Inicie el proceso con los siguientes parámetros:
@Override
protected String doIt() throws Exception {
this.processUI.ask("Yes or No?", new Callback<Boolean>() {
public void onCallback(Boolean result) {
addLog("You selected " + (result ? "Yes" : "No"));
}
});
return null;
}
5. Clases Modelos.
El primer paso es crear un nuevo modelo de clases en forma de dos tablas
de base de datos con una relación padre-hijo entre ellas.
Tabla Principal:
Cree la tabla principal eve_main de la siguiente manera:
-- User-defined columns
value character varying(40) NOT NULL,
name character varying(255) NOT NULL,
description character varying(255) NOT NULL,
help character varying(2000),
m_product_id numeric(10,0),
UNIQUE (ad_client_id, value)
);
Tenga en cuenta que las columnas con la restricción 'NOT NULL' se convertirán en
campos obligatorios en la ventana.
Tabla infantil:
Cree la tabla secundaria eve_sub siguiente:
-- User-defined columns
eve_main_id numeric(10,0) NOT NULL references eve_main(eve_main_id),
value character varying(40) NOT NULL,
name character varying(255) NOT NULL,
description character varying(255) NOT NULL,
help character varying(2000),
UNIQUE (ad_client_id, value)
);
Esto es como la tabla principal, excepto que tiene una relación de clave externa
con el padre.
Tabla y columnas
Iniciar sesión con el rol de System, después de iniciar sesión, seleccione el botón
crear tabla y columna a la derecha de la entrada Tabla y columna en la ventana
Favoritos. Cree la tabla introduciendo la tabla de base de datos principal en el
campo Nombre de tabla de base de datos. Guarde el registro de tabla y, a
continuación, haga clic en el engranaje Procesos para crear columnas a partir de la
tabla de base de datos, el proceso le pedirá que confirme que desea crear las
columnas, cuando el proceso se haya completado, enumerará las columnas que se
crearon, ahora tiene la nueva tabla y columnas para trabajar.
Ahora repita el ejercicio para crear una entrada de tabla para la tabla de base de
datos secundaria eve_sub y genere las columnas a partir de la base de
datos.Debemos vincular la tabla hija a su padre, utilizando la columna
EVE_Main_ID, así que selecciónela y ábrala, luego marque el atributo de columna
Enlace padre y guarde el cambio en la columna. Tenga en cuenta que podríamos
haber hecho lo mismo con la tabla principal EVE_Main anterior para vincularla a la
tabla M_Product también.
Ventana y pestañas
Hemos creado las entradas para las dos tablas, por lo que ahora podemos crear la
ventana y la pestaña para el EVE_Main padre y una subpestaña para el EVE_Sub
secundario.
Crear ventana
Haga clic en el botón para crear una nueva ventana (a la derecha de la entrada
Ventana, pestaña y campo en Favoritos) e ingrese el nombre.
Ahora debemos crear la subpestaña para la tabla secundaria, así que haga clic en
el icono Nuevo registro e ingrese los detalles para la subpestaña. Tenga en cuenta
que el nivel de tabulación debe establecerse en 1 porque es una subpestaña (el
nivel predeterminado es 0). Desplácese hacia abajo y haga clic en el icono Crear
campos para generar los campos para la subpestaña. Debe crear una entrada de
menú para usar la nueva ventana, así que haga clic en el botón para crear un nuevo
menú (a la derecha de la entrada de menú en Favoritos). Escriba el nombre,
establezca la Acción en Ventana y use el menú desplegable en Ventana para
encontrar la ventana que creó anteriormente y guarde el registro.
Plug-In
Archivo > nuevo > otro complemento de > > próxima >
Ahora navegue a la carpeta src del nuevo proyecto y cree un nuevo paquete.
Haga clic con el botón derecho en src > Nuevo paquete de >
● utilice el '...' en la carpeta de origen para buscar la carpeta src del proyecto
en el subdirectorio de complementos;
● El nombre del paquete es 'org.evenos.model';
● El nombre de la tabla es 'EVE_%' para generar modelos para ambas tablas;
● El tipo de entidad es 'U' para el usuario mantenido.
● Actualice el proyecto para ver las clases de modelo recién generadas.
Clases 'M'
Cree dos clases 'M' para mantener la lógica de negocios para cada una de las dos
tablas.
Haga clic con el botón derecho en org.evenos.model > Nuevo > Nombre de clase >:
MEVEMain > Finish
package org.evenos.model;
import java.sql.ResultSet;
import java.util.Properties;
/**
*/
private static final long serialVersionUID =
-4652910060540398746L;
package org.evenos.model;
import java.sql.ResultSet;
import java.util.Properties;
/**
*
*/
Para tener una idea de lo que la lógica de negocios es posible en estas clases, mire
las clases 'M' en el paquete 'org.compiere.model' en el proyecto
'org.adempiere.base', que es el núcleo de iDempiere.
Dependencias
El funcionamiento del nuevo plug-in depende de otros dos plug-ins, así que utilice
el botón Add... para añadir 'org.adempiere.base' y 'org.adempiere.plugin.utils' al
manifiesto del plug-in.
Fábrica de modelos
package org.evenos.factories;
import java.sql.ResultSet;
import org.adempiere.base.IModelFactory;
import org.compiere.model.PO;
import org.compiere.util.Env;
import org.evenos.model.MEVEMain;
import org.evenos.model.MEVESub;
@Override
if(tableName.equalsIgnoreCase(MEVESub.Table_Name))
return MEVESub.class;
if(tableName.equalsIgnoreCase(MEVEMain.Table_Name))
return MEVEMain.class;
return null;
@Override
if(tableName.equalsIgnoreCase(MEVESub.Table_Name))
if(tableName.equalsIgnoreCase(MEVEMain.Table_Name))
return null;
@Override
if(tableName.equalsIgnoreCase(MEVESub.Table_Name))
if(tableName.equalsIgnoreCase(MEVEMain.Table_Name))
Definición de componentes
Haga clic con el botón derecho en OSGI-INF > Nuevo > Otro... > Plug-in
Development > Component Definición > Nombre: ModelFactory.xml > Finish
Escriba lo siguiente:
Nota:
● El nombre es 'org.evenos.newwindow.model.factory'
● La clase es 'org.evenos.factories.MyModelFactory' (use el botón
Examinar para encontrarla)
● Haga clic en Agregar propiedad para crear la propiedad 'service.ranking'
con el tipo Integer y el valor 100, lo que garantizará que OSGi use la
fábrica de modelos personalizadas con preferencia a la versión
predeterminada
Ahora agregue IModelFactory a la lista de servicios proporcionados en la pestaña
Servicios de la Definición de componente:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Newwindow
Bundle-SymbolicName: org.evenos.newwindow
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.adempiere.base;bundle-version="4.1.0",
org.adempiere.plugin.utils;bundle-version="4.1.0"
Service-Component: OSGI-INF/*
6. Eventos.
Cómo desarrollar un EventHandler en su propio complemento para que
pueda compartir su complemento con otros con toda la información
necesaria para que funciones.
org.adempiere.base
org.adempiere.plugin.utils
org.adempiere.ui.zk
org.zkoss.zk.library
En este paso, creamos una clase que implementa IFormFactory, puede nombrarla
de acuerdo con sus preferencias. Por ejemplo, lo llamé HdSoftFormFactory y lo
coloqué dentro del paquete com.hdsoft.webui.factory. Esta clase está destinada a
ser utilizada como el cargador de formulario predeterminado de su complemento,
al que se llamará desde el servicio OSGI cuando haya una solicitud para crear un
formulario desde el cliente. En esta etapa aún no se ha definido interactuar con el
servicio OSGI. Simplemente agréguele un poco de código para que luego funcione
correctamente.