Está en la página 1de 141

ndice

CURSO DE X++

ndice

ndice
CURSO DE X++ INTRODUCCIN MTODOS CONTENEDORES Y SUS FUNCIONES SENTENCIAS BSICAS DEL LENGUAJE X++ INSTRUCCIONES DE ACCESO A REGISTROS JOBS ESTNDARES PARA LOS MTODOS DE LAS TABLAS MTODOS DISPLAY Y EDIT MTODOS BSICOS EN TABLAS CONTROL DE TRANSACCIONES HERRAMIENTAS DE DESARROLLO PROGRAMACIN DE FORMULARIOS PASO DE PARMETROS ENTRE OBJETOS: LA CLASE ARGS PROGRAMACIN DE INFORMES PLANTILLAS DE INFORMES CLASES DESARROLLO CLIENTE / SERVIDOR 1 4 8 17 19 27 37 38 41 44 51 54 61 79 82 94 95 107

ndice

OTRAS HERRAMIENTAS DE DESARROLLO COMUNICACIN CON EL USUARIO LA CLASE RUNBASE MAPS ACCESO A CLAVES DE FUNCIN DESDE EL CDIGO GESTIN DE EXCEPCIONES ACCESO A MEN ITEMS DESDE EL CDIGO INDICACIN DE OPERACIONES EN EJECUCIN XCLASES PERSONALIZANDO FORMULARIOS LOOKUP DEFINIDO. FUNCIONES GENERALES

109 117 125 131 133 134 137 138 139 ERROR! MARCADOR NO

140

Introduccin

Introduccin
1.
1.1.

El entorno MorphX
Definicin
El entorno de desarrollo en Navision Axapta se llama MorphX. Podemos considerarlo un entorno integrado de desarrollo (Integrated Development Environment IDE), porque integra muchas funciones diferentes, como diseo, edicin, compilacin y depuracin en un entorno comn. En herramientas de desarrollo ms tradicionales, cada una de estas funciones operara como un programa independiente, cada uno con su propia interfaz. MorphX permite al usuario modificar de un modo sencillo los objetos de la interfaz grfica. Al mismo tiempo que ofrece al usuario avanzado las herramientas necesarias para modificar fcilmente la funcionalidad de la aplicacin o bien crear diseos completamente nuevos. El rbol de objetos de la aplicacin (Application Object Tree AOT) es el elemento central desde el que el programador puede crear nuevos objetos o bien modificar los existentes. El desarrollador puede crear nuevos objetos utilizando la tcnica de arrastre (drag-and-drop) y asignndoles propiedades. Para hacer el trabajo del desarrollador ms fcil y rpido, el sistema tiene valores por defecto para todas las propiedades de los objetos de la aplicacin. Dado que se trata de un sistema de desarrollo orientado a objetos, el concepto de herencia es fundamental. La herencia significa que lo que se ha definido en niveles inferiores del sistema es automticamente heredado en niveles superiores. Un ejemplo claro del concepto de herencia es la posibilidad que tiene el desarrollador de modificar y aumentar la funcionalidad del sistema escribiendo sus propios mtodos. En Navision Axapta, la herencia no se limita nicamente a las clases, sino que se extiende a todo el sistema. De este modo, los objetos heredan no slo variables y mtodos, sino tambin propiedades.

1.2.

Conceptos Importantes en MorphX


Algunos trminos y mecanismos centrales orientados a objetos aparecen repetidamente cuando desarrollamos con MorphX. A continuacin vamos a dar una breve explicacin de los conceptos ms importantes.

1.2.1.

Clase de sistema
Una clase de sistema (system class) es una interfaz de funcionalidad definida en MorphX, por ejemplo para crear o ejecutar un formulario.

1.2.2.

Clase
Una clase (class) define las interfaces de un objeto. Ensea o explica como construir un objeto de un tipo particular.

Pgina 4 de 141

Introduccin

Una caracterstica esencial de una clase es que podemos crear nuevas instancias (objetos) de la clase. Los formularios, informes e incluso las tablas son ejemplos de clases: MorphX tiene una definicin de clase que define qu ocurre exactamente cuando un objeto de cada tipo es creado.

1.2.3.

Controles
Un control es un objeto grfico, como una caja de texto (text box), una casilla de verificacin (check box) o un botn de comando (command button) que podemos situar en un formulario o un informe cuando lo diseamos, para que nos muestre informacin, realice una accin o hacer el formulario o informe ms fcil de leer. Hay aproximadamente 20 controles diferentes y cada uno est definido por alrededor de 50 propiedades.

1.2.4.

Origen de datos
Un origen de datos (Data Source) contiene las variables de datos que utilizan un formulario o una consulta. Estas variables de datos pueden ser una o ms tablas, o campos individuales de las tablas.

1.2.5.

Diseos
Un nodo de diseos (Designs) proporciona acceso al usuario para definir el aspecto de un formulario o de un informe.

1.2.6.

Encapsulacin
La encapsulacin significa que los datos en el sistema son definidos dentro de los mtodos y solo pueden ser modificados desde los propios mtodos.

1.2.7.

Final
Final es un modificador de una clase o un objeto que indica que dicha clase o mtodo no puede ser ampliado o sobrecargado.

1.2.8.

Herencia
La herencia es un concepto fundamental en MorphX. Significa que lo que es definido en niveles inferiores del sistema es automticamente accesible, o lo que es lo mismo, heredado por los niveles superiores.

1.2.9.

Objetos
Los objetos son el concepto central de MorphX. Cualquier formulario y cualquier control es un objeto. La base de datos es tambin un objeto. En definitiva, cualquier cosa presente en el sistema es un objeto. Los objetos son creados a partir de las clases. Decimos por tanto que un objeto es una instancia de una clase.

Pgina 5 de 141

Introduccin

Los objetos proporcionan una forma lgica y conveniente de organizar los datos y los procedimientos. Los objetos estn encapsulados, lo que significa que contienen tanto su cdigo como sus datos. Para utilizar un objeto, debemos mantener una referencia a l mediante una variable del mismo tipo del objeto.

1.2.10. Mtodos
Los mtodos son tareas que podemos decir a un objeto que realice.

1.2.11. Propiedad
Las propiedades son datos que describen un objeto. Cada tipo de objeto tiene diferentes tipos de propiedades. Un mtodo tpicamente tiene unas pocas propiedades, una de las cuales, por ejemplo, define donde queremos que se ejecute. Por otra parte, un control tiene acerca de 50 propiedades que definen el color, el tamao, la posicin, etc.

1.2.12. Consulta
Una consulta es un mecanismo de filtrado para recuperar los datos que nos interesa ver a partir de las tablas de nuestra base de datos. Las consultas son utilizadas normalmente como el origen de datos en los formularios e informes.

2.
2.1.

El lenguaje X++
Introduccin
El lenguaje X++ es un lenguaje sencillo y fcil de aprender, para que pueda ser utilizado por la mayora de desarrolladores. Es un lenguaje orientado a objetos, para beneficiarse de las ventajas de las metodologas modernas de desarrollo de software, que se acopla perfectamente en aplicaciones cliente/servidor. Por ltimo, es un lenguaje interpretado, al estilo de Java, para obtener mximas capacidades dinmicas.

2.2.
a)

Caractersticas
Lenguaje simple, orientado a objetos y familiar

Las principales caractersticas de X++ son que se trata de un lenguaje sencillo que puede ser utilizado rpidamente, si se conoce la metodologa de la programacin orientada a objetos. Los conceptos fundamentales de X++ son asimilados rpidamente, por tanto los programadores pueden ser productivos desde el principio. X++ ha sido diseado desde su base para ser orientado a objetos. X++ proporciona una plataforma de desarrollo orientada a objetos limpia y eficiente. El lenguaje X++ utiliza principios de la programacin orientada a objetos como encapsulacin, herencia, clases, objetos, mtodos y propiedades.

Pgina 6 de 141

Introduccin

A pesar de que C++ y Java fueron rechazados como lenguajes para utilizar con MorphX, el aspecto de X++ es muy similar al de estos dos lenguajes, aunque se ha eliminado la complejidad innecesaria de estos lenguajes. Adems, como MorphX es una plataforma para construir complejos sistemas de gestin empresarial y contabilidad, el lenguaje X++ tambin incluye un gran nmero de comandos comunes de SQL como parte integrada del lenguaje. El hecho de que X++ tenga una sintaxis muy similar a lenguajes ya existentes como C++, Java o SQL hace que X++ sea un lenguaje familiar para la mayora de desarrolladores de software. Esto significa que pueden migrar rpidamente a este nuevo lenguaje. b) Lenguaje robusto

El lenguaje X++ ha sido diseado para crear software muy fiable. Proporciona comprobaciones muy amplias en tiempo de compilacin, seguidas de un segundo nivel de comprobaciones en tiempo de ejecucin. Las caractersticas del lenguaje dirigen a los programadores hacia unos hbitos de programacin fiable. El modelo de manejo de la memoria es extremadamente simple: los objetos son creados mediante un operador new. No existe un tipo de datos puntero definido por el programador de forma explcita, lo que implica que no necesitamos aritmtica de punteros ni tenemos la necesidad de realizar limpieza de punteros en memoria, con lo que resulta innecesarias las llamadas al mtodo finalize. Este sencillo modelo de manejo de memoria elimina gran cantidad de errores de programacin muy comunes entre los programadores de C y C++. Podemos desarrollar cdigo en el lenguaje X++ con la seguridad de que el sistema encontrar la mayora de los errores rpidamente y con la tranquilidad de que no tendremos problemas latentes no descubiertos hasta que nuestro cdigo est en circulacin en el mercado. c) Lenguaje de alto rendimiento

El rendimiento es siempre algo a tener en consideracin. El lenguaje X++ consigue un superior rendimiento adoptando un esquema de trabajo en el cual el intrprete puede trabajar a la mxima velocidad sin necesidad de comprobar el entorno en tiempo de ejecucin. El liberador de memoria automtico (automatic garbage collector), se ejecuta automticamente cuando es necesario, asegurando una probabilidad muy alta de que la memoria est disponible cuando se necesite, lo que se traduce en un mejor rendimiento. En general, los usuarios perciben que las aplicaciones interactivas responden ms rpidamente a pesar de que son interpretadas. d) Lenguaje interpretado y dinmico

En una plataforma interpretada como el lenguaje X++, la fase de enlazado de un programa es sencilla, incremental y ligera. De esta forma nos beneficiamos de unos ciclos de desarrollo y prototipado mucho ms rpidos, comparados con los pesados ciclos de compilacin, enlazado y pruebas tradicionales.

Pgina 7 de 141

Mtodos

Mtodos
1. Introduccin
Todo objeto puede identificarse por el estado en que se encuentra y por su comportamiento. En programacin, el estado de un objeto se define mediante variables, mientras que su comportamiento est definido por mtodos. Los mtodos actan sobre las variables del objeto haciendo evolucionar su estado. Las variables de un objeto slo son accesibles directamente por mtodos propios del objeto, nunca desde el exterior. En Axapta podemos encontrar mtodos en todos los objetos que componen la aplicacin, es decir, en: Tablas Formularios Informes Consultas Clases

En cada uno de estos objetos, los mtodos se crean del mismo modo que los elementos restantes de la aplicacin, es decir, utilizando el rbol de Objetos de la Aplicacin.

2.

Estructura de los mtodos


Un mtodo est formado por una cabecera y un cuerpo. ste, a su vez, est compuesto por la declaracin de variables y otras instrucciones. Seguidamente ilustramos la estructura de los mtodos:

Cabecera

Declaracin de variables Mtodo Cuerpo Declaracin de mtodos

Instrucciones

Pgina 8 de 141

Mtodos

2.1.

Cabecera
La cabecera de un mtodo tiene el siguiente aspecto (entre [] se muestran los valores opcionales):

[Modificador] TipoDatoRetorno NombreMtodo ([ListaParmetros])

Los modificadores y los parmetros se describen en apartados posteriores. El tipo de dato de retorno puede tomar los siguientes valores: Tipo de dato void : este trmino se utiliza cuando el mtodo no devuelve nada. anytype : significa que el mtodo puede devolver todos los tipos de datos (mediante distintas instrucciones de retorno en el cuerpo del mtodo) Siempre que un mtodo devuelva algn valor, se debe especificar el tipo del valor de retorno e incluir una instruccin de retorno (return ...).

2.2.

Cuerpo
El cuerpo de un mtodo tendr el siguiente aspecto: { [Declaracin de variables] [Declaracin de mtodos] [;] Instrucciones; }

Aunque no forma parte de la estructura de un mtodo, es recomendable aadir siempre una lnea con un punto y coma (;) antes del grupo de instrucciones. Esto es debido a que en algunas ocasiones, el compilador confunde una instruccin con la declaracin de una variable y devuelve un error de sintaxis en un mtodo cuyas instrucciones son completamente correctas. El nico modo de evitar este error es marcar el inicio del bloque de instrucciones con un punto y coma. Si revisamos algunos de los mtodos de la aplicacin estndar, observaremos que la mayora de ellos utilizan esta tcnica. La declaracin de variables y de mtodos se describe a continuacin. Las instrucciones se irn viendo a lo largo del curso.

Pgina 9 de 141

Mtodos

2.2.1.

Declaracin de variables

Una variable es un puntero a una posicin de memoria donde se almacena informacin de un tipo de datos especfico. Todas las variables deben ser declaradas antes de poder ser usadas. Hay que sealar que X++ no permite que la declaracin de variables se mezcle con otras instrucciones del lenguaje. En otras palabras, el lenguaje X++ requiere que las variables sean declaradas antes de cualquier otra instruccin. La sintaxis de la declaracin es la misma, tanto si es una variable simple o una variable de objeto. Las variables pueden ser declaradas de tres formas en X++: declaracin simple, declaracin con inicializacin y declaracin mltiple. a) Declaracin simple

La declaracin simple de variables es la ms utilizada, ya que es rpida y la mayora de variables son simples. La sintaxis es la siguiente: TipoDato IdentificadorVariable

TipoDato es cualquier tipo de datos del lenguaje X++. IdentificadorVariable es bsicamente un nombre cuyo primer carcter debe ser una letra que puede estar seguida por letras o nmeros. Como letras se consideran los caracteres a..z y el carcter subrayado (_). Para los tipos de datos, si se trata de un objeto de la aplicacin su nombre se escribir mezclando maysculas y minsculas, de manera que el primer carcter sea una mayscula as como la primera letra de cada palabra interna. Si se trata de un tipo de datos primitivo se escribir en minsculas. El nombre de una variable mezclar maysculas y minsculas, siendo la primera letra en minscula y el primer carcter de cada palabra interna en maysculas. A continuacin se muestran algunos ejemplos de declaracin de variables: int i; CustInvoiceJour custInvoiceJour;

La declaracin de variables de la mayora de tipos de datos de X++, exceptuando los objetos, tambin reserva un espacio de memoria para dichas variables. Cuando una variable es declarada adems se inicializa con un valor por defecto. b) Declaracin con inicializacin

En ocasiones nos interesa que una determinada variable tenga un valor distinto al valor por defecto, en el mismo instante en que la variable se crea. El lenguaje X++ permite la inicializacin de variables en la sentencia de declaracin. La inicializacin se lleva a cabo aadiendo una sentencia de asignacin a la declaracin de la variable.

Pgina 10 de 141

Mtodos

Un ejemplo de este tipo de declaracin sera el ejemplo siguiente, donde una variable real de nombre pi, es declarada e inicializada al valor del nmero Pi: real pi = 3.14159265359; Existe otra sintaxis para inicializar objetos, ya que estos son inicializados invocando el mtodo new de la clase. Un ejemplo de inicializacin sera el siguiente: Class classObject = new Class(); Lo que declarara un objeto llamado classObject de la clase Class y lo inicializara. c) Declaracin mltiple

A veces necesitamos varias variables del mismo tipo. En estos casos puede llegar a ser una prdida de tiempo tener que escribir el tipo de dato delante de cada variable que vayamos a declarar. Por este motivo, X++ nos permite declarar ms de una variable en la misma sentencia de declaracin. La sintaxis es la siguiente: TipoDato Variable {, Variable}

Un ejemplo sera de declaracin mltiple sera el siguiente: real a, b = 1.5; En esta sentencia se declaran dos variables de tipo real llamadas a y b, inicializando la variable b a 1.5. Dentro de un mtodo podemos hacer referencia al objeto al que pertenece el mtodo mediante la variable this. sta nos da acceso a todos los mtodos y propiedades de dicho objeto. Es utilizado normalmente como parmetro para los mtodos que necesitan una referencia al objeto.

2.2.2.

Declaracin de mtodos

Los problemas complejos del mundo real son a menudo ms fciles de resolver si los dividimos en problemas ms pequeos que puedan ser resueltos independientemente unos de otros. El lenguaje de programacin X++, nos permite introducir mtodos dentro de otros mtodos. Otros lenguajes como Java o C++ no soportan esta caracterstica. Aunque en la realidad no es una prctica comn. Los mtodos incrustados dentro de otros mtodos solo son visibles dentro del mbito en el cual son creados y definidos. Ejemplo void myMethod() { void myEmbeddedMethod() { Box(1, Este es un mtodo incrustado, 1); }

Box(1, Este es el mtodo principal, 1);

Pgina 11 de 141

Mtodos

myEmbeddedMethod(); } El mtodo llamado myEmbeddedMethod, tan solo estara visible desde el mbito en el que fue creado, es decir dentro del mtodo llamado myMethod.

2.2.3.

mbito de las variables en los mtodos

Las reglas relativas al mbito de las variables en X++ son muy sencillas, todos los mtodos tienen su propio mbito. Para usar datos de un mtodo a otro, o lo que es lo mismo, datos de mbitos diferentes, debemos trasladar los datos utilizando parmetros. Un mtodo puede tener uno o ms argumentos. Dentro del mbito de ese mtodo esos parmetros son tratados como variables locales, inicializadas con el valor que tena el parmetro en la llamada. Es importante sealar que todos los parmetros son pasados por valor. Esto significa que no podemos modificar el valor de la variable original, pero s el de la variable local en el mtodo, la cual es una copia de la original. A continuacin mostramos un ejemplo: void methodA(int i) { i = i + 1; print i; } void methodB() { int i = 3; print i; this.methodA(i); print i; } En este ejemplo el mtodo methodB tiene una variable local llamada i, la cual se utiliza como parmetro para llamar al mtodo methodA. El mtodo methodA utiliza un parmetro llamado i, por lo tanto tiene una variable local llamada i. Esta variable tiene el valor de la variable i del mtodo methodB, ya que ha sido utilizada como parmetro de la llamada. El resultado de invocar el mtodo methodB es la impresin del valor de la variable i del mtodo methodB antes y despus de la invocacin del mtodo methodA que imprime el valor de su variable local i. El resultado de la ejecucin es el siguiente: 3 4 3 Esto ilustra perfectamente que las dos variables i son distintas en cada mtodo y que el mtodo methodA no puede cambiar el valor de los parmetros fuera de su mbito.

Pgina 12 de 141

Mtodos

2.3.

Algunos ejemplos
La forma ms simple que puede tener un mtodo se muestra a continuacin: Ejemplo 1 void methodName() { } Este ejemplo muestra un mtodo que no devuelve nada (void) y que no utiliza parmetros (los parntesis estn vacos). Adems, el cuerpo del mtodo (entre llaves) est vaco. El ejemplo es una declaracin vlida de un mtodo, pero como no hay instrucciones en el cuerpo, el mtodo no har nada. Ejemplo 2 int methodName() { return 1 } Si el mtodo debe devolver algo, por ejemplo un entero, la declaracin debe parecerse al ejemplo 2. La palabra int antes del nombre del mtodo, indica que el mtodo devolver un entero y la instruccin return 1 en el cuerpo devuelve el valor entero 1 al elemento que ha llamado al mtodo. Esto significa que se puede utilizar el resultado de la llamada al mtodo en una expresin, asignacin o incluso como parmetro en una llamada a otro mtodo. Un mtodo un poco ms complejo (sin argumentos ni modificadores) es por ejemplo, el mtodo delete de la tabla de proveedores. Mtodo delete en la tabla VendTable void delete() { Address address; ttsbegin; //Comienza la transaccin super(); //Llamada al mtodo delete de la clase superior

//Selecciona todas las direcciones para ese proveedor while select address where address.AdrTableId == this.TableId && address.AdrRecId == this.RecId { address.delete(); //Llamada al mtodo delete } ttscommit; //Acepta la transaccin

Pgina 13 de 141

Mtodos

} En el ejemplo podemos ver la cabecera del mtodo sin modificadores ni argumentos. A continuacin tenemos la declaracin de una variable llamada address. Al lado de cada instruccin se ha descrito su funcin mediante un comentario. Una lnea de comentario se marca mediante los caracteres //, mientras que un bloque de comentarios debe enmarcarse entre los caracteres /* y */.

3.
3.1.

Parmetros
Definicin
En algunas ocasiones son necesarios datos externos para utilizarlos en un mtodo, y la nica forma de realizar esto es definiendo datos de entrada al mtodo conocidos como parmetros. Si se utilizan parmetros en un mtodo, el mtodo puede escribirse a menudo de una manera ms general, lo que significa que tendr que escribirse menos cdigo para llevar a cabo una tarea. Como se describe en un apartado anterior, los parmetros en los mtodos son declarados en la declaracin del mtodo. Posteriormente son utilizados cuando se realiza una llamada al mtodo. La lista de parmetros que se declara en la cabecera de un mtodo estar compuesta por uno o ms parmetros separados por comas. La declaracin de cada uno de los parmetros tiene la siguiente estructura: TipoDato NombreParmetro [=Expresin] Es decir, los parmetros se declaran como si se tratar de una declaracin normal de variables. Como ejemplo de un mtodo que devuelve algo y utiliza parmetros podemos ver la declaracin del siguiente mtodo de la tabla CustTable:

Boolean chekDimension(Dimension dimension) { } El mtodo checkDimension devuelve un booleano y utiliza un parmetro del tipo de datos extendido Dimension, que es un vector de cadenas de caracteres.

3.2.

Parmetros opcionales
Es posible inicializar los parmetros en la declaracin. Esto convierte al parmetro en un parmetro opcional, de modo que si no es utilizado en la llamada al mtodo se utiliza el valor de la inicializacin.

Pgina 14 de 141

Mtodos

Veamos un ejemplo: Sea una clase Human, cuyo mtodo new tiene el siguiente aspecto (cuando veamos las clases hablaremos con ms detalle de este mtodo, de momento simplemente indicaremos que permite crear e inicializar las variables de un objeto): void new (Date _birthdate) { birthdate = _birthdate; } Es decir, al crear un objeto de la clase Human, simplemente estamos asignando el valor del parmetro a la variable birthdate. A continuacin, definimos un mtodo que calcula la edad en aos a partir de una fecha que se puede especificar como parmetro. Este parmetro es opcional, es decir, si no pasamos una fecha en la llamada al mtodo tomar como fecha de clculo la fecha de hoy: real age(date _calcDate = today()) { return (_calcDate - this.birthdate)/365; } Veamos las distintas posibilidades de llamada al mtodo:

Human kid = new Human(1/1/90); // Crea un objeto de tipo Human print kid.age(); //Imprime la edad a fecha de hoy print kid.age(1/1/1991); //Imprime la edad a fecha 1/1/91

4.

Modificadores
Existen diferentes modificadores que pueden ser aplicados en la declaracin de mtodos. Son los siguientes: a) Static Crea un mtodo de clase que no puede operar sobre un objeto. b) Final Crea un mtodo que no puede ser sobrecargado por subclases. No puede ser aplicado a los mtodos new y finalize. c) Display Los mtodos de este tipo siempre devuelven un valor. Se utilizan para asignar un valor a un campo en un informe o en un formulario. El campo no puede ser modificado.

Pgina 15 de 141

Mtodos

d)

Edit Los mtodos de este tipo siempre devuelven un valor. Se utilizan para asignar un valor a un en un formulario, que puede ser modificado.

Tal y como se vio en un apartado anterior, los modificadores forman parte de la cabecera de un mtodo, y se utilizan justo antes del tipo de datos de retorno. Como ejemplo, veamos algunas cabeceras de mtodos: static void ClassNoChange() final int DontAlterMe() display int Value() El modificador final se ver ms adelante, en el captulo dedicado a clases. Los modificadores display y edit tienen dedicado su propio captulo. Los mtodos de tipo static se describen en el siguiente apartado.

5.

Mtodos estticos
Los mtodos estticos nunca operan sobre un objeto, es decir sobre una instancia de la clase en ejecucin. Podemos ver muy fcilmente con un ejemplo el significado de los mtodos estticos. Supongamos un mtodo exist que recibe como parmetro un cdigo de cliente y nos indica si el cliente existe o no. Si el mtodo actuara sobre un objeto, no tendra ningn sentido, ya que para ejecutar el mtodo debera existir el objeto y por lo tanto el resultado sera siempre s. La declaracin de este mtodo podra tener la siguiente cabecera: static Boolean exist (CustAccount _custAccount) Dado que un mtodo esttico no opera sobre un objeto, no podemos utilizar la variable this. Por otro lado, y dado que se trata de mtodos de clase, nunca pueden ser sobrecargados. Como regla general de diseo en un entorno orientado a objetos y cliente/servidor, un mtodo se declarar como esttico cuando no tiene acceso a los miembros (variables y mtodos) de la instancia y, por lo tanto no utiliza el puntero this, y no va a ser sobrecargado. Como los mtodos estticos no operan sobre los objetos, no pueden ser llamados como cualquier otro mtodo no esttico. Por lo tanto tenemos que llamarlos utilizando el operador de mbito (scope-operator) ::, como en el siguiente ejemplo: ClassName::myMethod() Dentro de una clase, es posible declarar un mtodo esttico y un mtodo no esttico con el mismo nombre. Como por ejemplo: void myMethod() { // Instrucciones }

Pgina 16 de 141

Mtodos

static void myMethod() { // Instrucciones } En este caso tendramos dos mtodos con el mismo nombre, sin embargo como uno de ellos es esttico no se invocaran de la misma manera. Por ejemplo, className.myMethod() invocara el mtodo de la instancia actual de la clase, es decir el mtodo del objeto, mientras que ClassName::myMethod() invocara el mtodo esttico de la clase, con lo que no existe confusin posible.

En un entorno cliente/servidor, es interesante reducir al mximo el trfico en la red. Desde este punto de vista, resulta ms baratos llamar a un mtodo esttico de forma remota que instanciar un objeto y despus llamar a uno de sus mtodos.

Contenedores y sus funciones


1. Definicin
X++ tiene un tipo de datos general llamado contenedor (container), que puede ser considerado como un vector dinmico indefinido de tipos de datos primitivos, contenedores y vectores. Los contenedores pueden ser utilizados para guardar una lista de elementos de diferentes tipos y son especialmente tiles para situaciones intermedias. Los contenedores son dinmicos y no tienen lmite. Pueden contener elementos de casi todos los tipos de datos: booleano, entero, real, fecha, cadena, contenedor, vector, tablas y tipos de datos extendidos. Las variables de objetos y los campos de las tablas pueden ser declarados como contenedores.

2.

Declaracin de variables de tipo contenedor


Los contenedores se declaran utilizando la palabra reservada container seguida de la variable que lo identifica. Ejemplos de declaracin de containers: container c1; // declaracin de un container container c2[]; // declaracin de un vector de containers dinmico container c3 = [ 1, 3.14, a]; // declaracin e inicializacin de un container con 3 elementos: un entero, un real, y una cadena.

Pgina 17 de 141

Mtodos

3.

Funciones que utiliza un contenedor


En la siguiente tabla se presentan algunas de las funciones que utilizan los contenedores. En el nodo Funciones de la Documentacin del sistema podemos encontrar ayuda acerca de estas funciones.

Nombre ConDel( container, int, int)

Descripcin Eliminacin de un nmero especfico de elementos de un contenedor. El primer entero especifica la posicin inicial a partir de la que se van a eliminar elementos. El segundo indica el nmero de elementos a borrar. Devuelve un contenedor.

ConFind ( container, element, Localiza la primera ocurrencia del elemento pasado como .) parmetro entre los elementos de un contenedor. Devuelve 0 si no ha encontrado el elemento, o el n de posicin que ste ocupa en el contenedor. ConIns element) (container, int, Inserta un elemento en un contenedor, en la posicin que le pasamos como parmetro. Devuelve el nuevo contenedor. Devuelve el nmero de elementos que tiene el contenedor. Devuelve un contenedor vaco. Devuelve el elemento del contenedor que ocupa la posicin que le hemos pasado como parmetro. int, Reemplaza el/los elemento/s del contenedor a partir de la posicin que se le pasa como parmetro. Si deseamos reemplazar varios elementos los pondremos seguidos de comas. Devuelve el contenedor con los elementos reemplazados.

ConLen ( container) ConNull ( ) ConPeek (container, int)

ConPoke element)

(container,

Pgina 18 de 141

Sentencias bsicas del lenguaje X++

Sentencias bsicas del lenguaje X++


1. Introduccin
El hecho de que X++ tenga una sintaxis muy similar a lenguajes ya existentes como C++, Java o SQL hace que X++ sea un lenguaje familiar para la mayora de desarrolladores de software. Esto significa que pueden migrar rpidamente a este nuevo lenguaje y pueden ser productivos desde el primer momento. En el presente captulo vamos a revisar brevemente algunas de las instrucciones ms comunes. Si se considera necesario, esta informacin se puede ampliar consultando la Gua de ayuda al desarrollador de Axapta.

2.

Operadores
Significado
Igual a Distinto de Mayor que Mayor o igual que Menor que Menor o igual que No

Operador
== != > >= < <= !

Operador
&& ||

Significado
Funcin Y Funcin O

3.
3.1.

Sentencias condicionales
Instruccin IF
Normalmente queremos hacer diferentes cosas con datos distintos. Para hacer esto posible, necesitamos decidir en funcin de una condicin. Una instruccin if evala una condicin y ejecuta un conjunto de instrucciones dependiendo del valor lgico de esa condicin. La instruccin if es la instruccin de bifurcacin ms simple que ofrece el lenguaje X++, y est definida de la siguiente forma: if ( expresin ) instrucciones [ else instrucciones ]

Pgina 19 de 141

Sentencias bsicas del lenguaje X++

La expresin entre parntesis (la condicin), puede ser cualquier expresin que pueda evaluarse a verdadero o falso. Hay que recordar que cualquier nmero diferente de 0 y cualquier cadena de caracteres no vaca se interpreta como un valor cierto, mientras que solo vamos a considerar como valor falso cuando tengamos un nmero igual a 0 o cadena de caracteres vaca. A continuacin presentamos dos ejemplo de instruccin if: Sin Else 1) if (a>4) print a; 2) if (Debtor.NameRef == Uptown Radio) print Great music; 3) if (bankAccountTrans) { sentencias} 4) if (!this.validation()) { throw error("@SYS18447"); }

Con Else 1) if (a>4) print a; else print 4 es mayor que a; 2) if (BankAccountTable::Find(AccountId).Name) print Cuenta existente; else print No existe la cuenta;

El lenguaje permite anidar sentencias if unas dentro de otras.

3.2.

Instruccin SWITCH
La sentencia switch es una sentencia de bifurcacin mltiple. Eso significa que podemos seguir ms de dos caminos utilizando esta sentencia, en contraste con la instruccin if. En una instruccin switch, normalmente queremos que ocurra algo por defecto, si no se elige ninguna de las alternativas correspondientes a los distintos caminos posibles a seguir. Por tanto, existe un camino por defecto que se sigue si no se ha elegido ninguno de los otros posibles.

Pgina 20 de 141

Sentencias bsicas del lenguaje X++

Dependiendo de una condicin que se evala, la ejecucin del programa salta al camino correcto y contina la ejecucin desde all. Si queremos que la ejecucin se pare en algn lugar determinado dentro de la instruccin switch debemos utilizar la sentencia break. La sintaxis es la siguiente: switch (Expresin) { case Expresin {, Expresin}: Instrucciones; [break;]

case ...

[defaut Instrucciones; ] }

Un ejemplo de una instruccin switch, en comparacin con una instruccin if, sera el siguiente: Ejemplo instruccin switch switch (i) { case 10: // Instrucciones A; break; case 20: // Instrucciones B; break; default: // Instrucciones C; break; } Ejemplo instruccin if if (i==10) // Instrucciones A; else if (i==20) // Instrucciones B;

Pgina 21 de 141

Sentencias bsicas del lenguaje X++

else //Instrucciones C; Como podemos ver, en estos casos la instruccin switch es mucho ms intuitiva y fcil de entender que la instruccin if. Es importante sealar que si no utilizramos la instruccin break, la ejecucin del programa continuara con las instrucciones correspondientes a los siguientes caminos de ejecucin definidos en la instruccin switch. Ejemplos de Switch 1) switch (budget.tableId) { case tablenum(LedgerBudget): return new BudgetExpansion(budget); case tablenum(ForecastSales),tablenum(ForecastPurch): return new ForecastExpand(budget); case tablenum(ProjBudgetEmpl): return new BudgetExpansion(budget); case tablenum(ProjBudgetCost): return new BudgetExpansion(budget); case tablenum(ProjBudgetRevenue): return new BudgetExpansion(budget); } 2) switch (f) { case 2 : label = rd.lookupLabel(literalStr("@SYS53635")); break; case 3 : label = rd.lookupLabel(literalStr("@SYS3794")); break; case 4 : label = rd.lookupLabel(literalStr("@SYS50253")); break; case 5 : label = rd.lookupLabel(literalStr("@SYS477")); break; case 6 : label = rd.lookupLabel(literalStr("@SYS6437")); break;

Pgina 22 de 141

Sentencias bsicas del lenguaje X++

Defualt : Throw error Caso desconocido; }

3.3.

Operador ternario: ?
A veces necesitamos elegir entre dos expresiones dependiendo de alguna condicin concreta. Eso puede realizarse utilizando la instruccin if estndar antes comentada. Esto nos obligara a realizar dos grupos de instrucciones, sin embargo el operador ternario (?) se puede ahorrrar cdigo. La sintaxis de este operador se presenta a continuacin: Expresin ? Expresin : Expresin

Si la primera expresin es verdadera, devolveramos la expresin situada inmediatamente detrs del smbolo ?, por el contrario, si es falsa devolveramos la expresin situada detrs de los dos puntos (:). La funcionalidad es similar a la de la instruccin if, pero mientras que en sta podemos elegir entre dos grupos de instrucciones, con el operador ternario podemos elegir entre dos expresiones. Las ventajas del operador ternario con respecto a la instruccin if se ilustran en el siguiente ejemplo: Operador ternario int result; int choose = 3; ; result = choose > 3 ? 100 : 50; Instruccin if int result; int choose = 3; if (choose > 3) result = 100; else result = 50; Como podemos ver con el operador ternario el cdigo es ms corto y adems podemos devolver el resultado de una manera directa, lo que hace aconsejable su utilizacin en determinadas ocasiones.

4.
4.1.

Sentencias de repeticin
Instruccin WHILE
A menudo necesitamos repetir algo mientras que una expresin sea verdadera. Si por ejemplo, estamos leyendo un fichero de texto, debemos seguir leyendo mientras haya ms texto en el fichero, es decir, antes de alcanzar el fin del fichero.

Pgina 23 de 141

Sentencias bsicas del lenguaje X++

Una instruccin while slo se ejecuta si la condicin es verdadera. Esto significa que una instruccin while puede ejecutarse varias veces, una vez o incluso ninguna, dependiendo de la condicin inicial. La sintaxis es la siguiente: while ( Expresin ) Instrucciones

Ejemplos de la instruccin while. 1) int n = 10; while (n > 1) { // Instrucciones n = n - 1; } 2) while (queryCust.next()) { Sentencias } 3) while select custInvoiceJour ==

where (custInvoiceJour.invoiceAccount custTable.accountNum && invoiceCustomer)

4.2.

Instruccin DO WHILE
La instruccin dowhile tiene la misma funcionalidad bsica que la instruccin while, pero se diferencia en que la condicin se comprueba despus de las instrucciones. Esto significa que una instruccin dowhile al menos se ejecuta una vez, aunque puede hacerlo varias veces dependiendo de la condicin. La sintaxis es la siguiente: do { { Instrucciones } } while ( Expresin ) A continuacin presentamos un ejemplo de instruccin dowhile. int n = 1; do { // Instrucciones n = n + 1; } while (n < 1)

Pgina 24 de 141

Sentencias bsicas del lenguaje X++

En este caso el conjunto de instrucciones situadas dentro del cuerpo de la instruccin dowhile se ejecutara una vez.

4.3.

Instruccin FOR
La instruccin for es una instruccin while extendida, que resulta especialmente til cuando estamos trabajando con vectores (arrays), ya que la condicin es una variable que se va incrementando en cada iteracin. Realmente, la instruccin for aade funcionalidad a la instruccin while, ya que nos da la posibilidad de asignar un valor inicial a la variable de control de la condicin y de definir una instruccin de incremento o decremento de dicha variable. En cualquier otro aspecto, una instruccin for puede ser considerada de la misma forma que una instruccin while. La sintaxis es la siguiente: for ( Inicializacin; Expresin; Actualizacin ) Instrucciones Es importante sealar que la inicializacin y la actualizacin son dos instrucciones regulares de X++, pero el uso normal de esas instrucciones en la sentencia for es inicializar y actualizar la variable de control respectivamente. Vamos a mostrar a continuacin un ejemplo que compara el uso de las instrucciones for con las instrucciones while. Instruccin for int i; for (i=1; i<=100; i=i+1) { print i; } Instruccin while int i; i = 1; while (i<=100) { print i; i=i+1; } Como podemos apreciar, conseguimos ahorrarnos algo de cdigo en el caso de la instruccin for, aunque el funcionamiento es totalmente anlogo.

Ejemplos de For:

Pgina 25 de 141

Sentencias bsicas del lenguaje X++

1) for (i=0; i<dictEnum.values(); i++) { sentencias } 2) for (i=1; i<=conlen(c); i++) { sentencias }

Pgina 26 de 141

Instrucciones de acceso a registros

Instrucciones de acceso a registros


1. Introduccin
El lenguaje X++ integra comandos comunes de SQL que facilitan en gran medida el acceso a los datos almacenados en las tablas de la aplicacin y el manejo de los mismos. La sintaxis de estos comandos es muy similar a la del lenguaje SQL, por lo tanto resultar familiar para la mayora de desarrolladores de software

2.

Instruccin SELECT
La mayora de los procesos que se programan suponen la manipulacin de los datos almacenados en las tablas y, por lo tanto, el acceso a la base de datos. Por esta razn, existe en X++ la instruccin select, que es probablemente la instruccin ms potente y ms ampliamente utilizada en el lenguaje. La instruccin select tiene como propsito buscar y manipular los datos de la base de datos. Para ello utiliza una variable de tipo tabla, que debe ser declarada antes de que pueda ser ejecutada la instruccin select. El resultado de la seleccin de registros se devuelve en esta variable, que por lo tanto es utilizada para manipular los datos. Mediante una sentencia select recuperamos un grupo de registros de la base de datos, aunque en cada momento slo tenemos acceso a uno de ellos. Para manipular otros registros del grupo, debemos desplazarnos a travs de l mediante la instruccin next. Hablando tcnicamente, la instruccin select crea un cursor que puede avanzar al siguiente registro mediante la instruccin next. La sintaxis es la siguiente: InstruccinSelect = select Parmetros

Parmetros = [ [OpcionesBsqueda] [ListaCampos from] ] VariableTabla [InstruccinIndice] [Opciones] [InstruccinWhere] [instruccinJoin] OpcionesBsqueda nofetch = reverse | findfast | firstonly | forupdate | | * | IdentificadorCampo | count

ListaCampos = Campo {, Campo} Campo Clculo

= Agregar ( IdentificadorCampo) = sum | | avg | minof |

maxof

Opciones = ( order by [Direccin]

group by ) IdentificadorCampo

{, IdentificadorCampo [Direccin]} InstruccionesIndice Direccin InstruccinWhere = asc = index idx | desc | index hint idx

= where Expresin

Pgina 27 de 141

Instrucciones de acceso a registros

InstruccinJoin Parmetros

= [ exist

not exist

outer ] join

A continuacin, veamos un ejemplo de instruccin select. void selectRecords() { MyTable myTable;

select * from myTable order by TableCode where TableCode > 100; } En el anterior ejemplo, seleccionamos todos los registros de la tabla llamada MyTable que tienen un valor mayor que 100 en el campo TableCode, y devolvemos el primero de ellos en la variable myTable.

Cuando deseamos acceder nicamente a un nmero reducido de campos de la tabla es ms apropiado, desde el punto de vista de la eficiencia del sistema, especificar la lista de campos que acceder a registros completos. Por lo tanto, y segn la nota anterior, en el ejemplo siguiente, el mtodo methodA sera mucho ms eficiente que el mtodo methodB: void methodA { CustTable custTable; ; select * from custTable;

while (custTable.accountNum) { print custTable.accountNum; next custTable; } }

void methodB { CustTable custTable; ; select accountNum from custTable;

Pgina 28 de 141

Instrucciones de acceso a registros

while (custTable.accountNum) { print custTable.accountNum; next custTable; } } Tambin podemos utilizar la sentencia next sin necesidad de tener una instruccin select previa. En estos casos se comporta como si hubiramos realizado un select implcito sin clusula where. Por ejemplo: Ejemplo 1 { MyTable myTable; next myTable; } Ejemplo 2 { MyTable myTable; select * from myTable; } En ambos casos el resultado sera el mismo. Tendramos el primer registro de la tabla MyTable en la variable myTable.

2.1.

Opciones de bsqueda
Al describir la sentencia select, se han nombrado una serie de opciones de bsqueda que se describen a continuacin: reverse: los registros son devueltos en orden inverso firstfast: esta opcin acelera la captura de los registros. En realidad, devuelve la primera fila ms rpidamente, pero el tiempo total de acceso puede ser mayor. Esta opcin suele utilizarse en actualizaciones de dilogos. firstonly: slo devuelve el primer registro que cumple la condicin de seleccin. forupdate: selecciona los registros para ser actualizados. Es decir, los registros accedidos son modificados y posteriormente se actualiza la base de datos. Dependiendo del gestor de base de datos, los registros pueden quedar bloqueados de forma que otros usuarios no puedan acceder simultneamente. nofetch: indica que los registros no van a ser accedidos por el momento. Se utiliza cuando el resultado de la seleccin se pasa a otro objeto de la aplicacin.

Pgina 29 de 141

Instrucciones de acceso a registros

2.2.

Opciones de clculo
Las posibles opciones de clculo que presenta la sentencia select se describen a continuacin: sum: suma avg: media minof: mnimo maxof: mximo count: nmero de registros Todas estas funciones realizan el clculo sobre las filas agrupadas segn la sentencia group by.

Si deseamos realizar un clculo sobre un campo de una tabla, es mucho ms eficiente utilizar las opciones de clculo de la instruccin select que seleccionar el grupo de registros, recorrerlos uno a uno y realizar el clculo en nuestro cdigo. La razn de esto es fcil de entender si tenemos en cuenta que la instruccin select la ejecuta el servidor de base de datos. En SQL estndar, si ningn registro de la tabla cumple las condiciones de seleccin, el resultado es una fila, cuya columna count vale 0 y las restantes funciones de clculo devuelven NULL. Dado que Axapta no soporta el concepto de valores NULL, si ningn registro cumple las condiciones de seleccin, no devuelve ninguna fila al usuario. Sin embargo, si la nica funcin de clculo que se ha utilizado es count, se devolver una fila (como indica el lenguaje SQL estndar) con valor 0 en el campo utilizado en la funcin count. Si la instruccin select contena una lista de campos, stos tomarn el valor NULL en el sentido en que lo toma Axapta. En Axapta, cada tipo de datos tiene asignado un valor que se interpreta como valor NULL bajo determinadas circunstancias:

Tipo de datos Cadena Entero Real Fecha Hora Enumerado

Valor NULL (cadena vaca) 0 0.0 01/01/1901 00:00:00 primer valor

Pgina 30 de 141

Instrucciones de acceso a registros

En la mayora de los casos, para saber algn registro cumple las condiciones de seleccin, se consulta si el valor del campo RecId del registro es no nulo.

2.3.

Orden de los registros


Cuando el orden de los datos es importante, debemos utilizar order by en las instrucciones select. Adems, si creemos que la base de datos no va a ser capaz de decidir que ndice debe utilizar para buscar los datos, debemos utilizar la palabra index para indicarle el ndice a utilizar. Debemos combinar estas dos expresiones para conseguir que MorphX seleccione los registros en un orden especfico. Utilizaremos la palabra index conjuntamente con order by, si queremos asegurarnos que el orden de los registros es el que a nosotros nos interesa. Sin embargo no utilizaremos order by, si nicamente necesitamos obtener los registros seleccionados en el orden definido por el ndice. En general, los ndices los utilizaremos para optimizar la seleccin de registros. A continuacin presentamos un ejemplo: void selectRecords() { MyTable table;

select * from table index tableIdx order by TableCode where TableCode > 100; } En este ejemplo seleccionaramos todos los registros de la tabla que tuvieran un valor mayor que 100 en el campo TableCode, ordenados por ese campo y utilizando como ndice el definido en la tabla de nombre tableIdx.

2.4.

Relaciones entre tablas


Cuando queremos seleccionar datos que provienen de dos tablas relacionadas, debemos utilizar la palabra join. Es muy importante que ambas tablas estn relacionadas para obtener los datos correctos. Sin embargo, las relaciones que se hayan definido en el rbol de objetos no se heredan cuando realizamos un join, por tanto en la instruccin select hay que hacer una definicin explcita de las igualdades que nos construyen dichas relaciones. A continuacin presentamos un ejemplo de instruccin select que obtiene datos de dos tablas relacionadas mediante un join. Ejemplo de utilizacin de join MyTable tableA;

OtherTable tableB;

select * from tableA where FieldValue > 100

Pgina 31 de 141

Instrucciones de acceso a registros

join tableB where tableA.TableCode == tableB.TableCode //Se especifica la relacin entre tablas Esta instruccin obtendra todos los registros de la unin de las tablas tableA y tableB, que tuvieran un valor mayor de 100 en el campo FieldValue. La relacin entre las tablas se realiza con la igualdad de la instruccin tableA.TableCode == tableB.TableCode, siendo estos los campos comunes entre ambas tablas. Pueden definirse distintos tipos de relaciones entre tablas, que se corresponden con los tipos de uniones definidos en la creacin de formularios: join: Selecciona los registros de la tabla principal que tienen registros asociados en la tabla relacionada. Es decir, en el resultado tendremos un registro principal por cada registro relacionado. Corresponde con la opcin InnerJoin en la construccin de formularios. exist join: Selecciona un registro de la tabla principal si existen registros relacionados en la tabla asociada. Este tipo de unin se diferencia del anterior en que slo devuelve el primer registro que encuentra en la tabla relacionada. not exist join: Selecciona los registros de la tabla principal que no tienen registros asociados en la tabla relacionada. outer join: Selecciona registros de la tabla principal tengan o no registros asociados en la tabla relacionada.

3.

Ejemplos de SELECT
Todos los ejemplos usan la tabla Custtable, por lo tanto comenzamos declarando una variable de cliente pero, lgicamente, puedes usar la tabla que se quiera. Para ilustrar el trabajo de las sentencias select, asume que la tabla de clientes slo tuviera 5 registros (muchos campos han sido quitados): AccountNo 100 200 300 4000 5000 NameRef Radio Uptown CBS Walt Disney Ford Motor Company Pentagon Balance $ 10,000 $ 20,000 $ 30,000 $ 5,000 $ 1,000,000 Invoice No Blocked No No No

void SelectRecordExamples() {

Pgina 32 de 141

Instrucciones de acceso a registros

CustTable custtable;

//Un cliente es encontrado y retornado a Custtble select * from Custtable;

// Un cliente con el cdigo > 100 select * from Custtable where AccountNo > 100;

// El cliente con el menor nmero > 100 es encontrado, // este es , CBS con el nmero 200. select * from Custtable order by AccountNo where AccountNo > 100; next Custtable; // El cliente siguiente en ser ledo, por Ejemplo Walt Disney

// El cliente con el mayor nmero de cuenta // (mayor de 100) es encontrado: Pentagon select * from Custtable order by AccountNo DESC where AccountNo > 100; next Custtable; // El siguiente registro ledo es (DESC) = Ford Motor

// El cliente con el mayor nmero de cuenta es: Pentagon select reverse Custtable order by AccountNo;

// EL cliente con el menor nombre y nmero de cuenta // en el intervalo ]100;1000[ es encontrado. Este es CBS. select * from Custtable order by NameRef where AccountNo > 100

Pgina 33 de 141

Instrucciones de acceso a registros

&& AccountNo < 1000;

// La seleccin COUNT retorna el nmero de clientes accountnumbers (clientes): 5 select count(AccountNo) from CustTable; print Custtable.AccountNo; // Imprime el resultado del count // (el cual est en AccountNo)

/* Retorna la suma de los balances para los clientes no bloqueados. El resultado es: SUM: $1,060,000 */ select sum(Balance) from Custtable where Blocked == DebCreBlocked::No; }

Una nota para el siguiente comando: Hay que darse cuenta que cuando el comando NEXT es usado sin estar precedido de un select, es tratado como si hubiera un comando SELECT implcito sin una clusula Where. Ejemplo: { MyTable T; // declara una instancia de MyTable Next T; // recupera el primer registro, si lo hay, de la tabla MyTable }

Esto equivale a:

{ MyTable T; // declara una instancia para MyTable Select T; // recupera el primer registro, si lo hay, de la tabla MyTable

Pgina 34 de 141

Instrucciones de acceso a registros

} En el ltimo ejemplo, una llamada a NEXT retornara el segundo registro del resultado. Field Select Nota que tambin es posible usar una sentencia select en un lookup en un campo: despus de un sentencia select que va a buscar un registro en una tabla, puedes escribir .nombre de campo para referenciarte a un campo de una tabla. Debajo encontrars ejemplos de esta seleccin de campos. Nota, que esas selecciones deben ser usadas en las expresiones! Void selectFieldExample () { //imprime el campo NameRef para el cliente seleccionado (el cual es CBS) print (select Custtable order by NameRef).NameRef; Usa el campo de balance para el cliente con una cuenta 5000 (Pentagon). //Imprime un mensaje. if ((select Custtable where AccountNo == 5000).Balance > 500000) print This customer has a balance above $500,000; } Date cuenta de la diferencia entre la seleccin normal y la de seleccin de campo. La se seleccin de campo opera directamente sobre la tabla mientras que la seleccin opera sobre una variable de la tabla.

4.

Instruccin WHILESELECT
La instruccin whileselect itera sobre un grupo de registros, que cumplen ciertas condiciones de seleccin, de manera que es posible realizar operaciones sobre cada registro. La ventaja de la instruccin whileselect, es que es capaz de desplazarse automticamente por todos los registros seleccionados (por tanto no necesitamos la instruccin next) y ejecuta instrucciones para cada uno de estos registros. Esta versin de instruccin de seleccin de registros es la ms utilizada en MorphX. Cuando estamos manipulando datos utilizando esta sentencia, normalmente debemos utilizar el concepto de transaccin para asegurarnos la integridad de los mismos. La sintaxis es la siguiente:

Pgina 35 de 141

Instrucciones de acceso a registros

while { }

InstruccinSelect

A continuacin presentamos un ejemplo: void selectRecords() { MyTable table;

while select * from table order by TableCode where TableCode > 100 { print table.TableCode; } } En este ejemplo seleccionaramos todos los registros de la tabla que tuvieran un valor mayor que 100 en el campo tableCode, ordenados por ese campo e imprimiramos su valor.

5.

Instruccin DELETE_FROM
Podemos utilizar la instruccin delete_from para borrar todos los registros que cumplan una determinada condicin. Esta instruccin es equivalente a ejecutar una instruccin whileselect y realizar el borrado en cada uno de los registros. Instruccin whileselect { MyTable myTable;

while select myTable where ... { myTable.delete(); } } Instruccin delete_from { MyTable myTable;

Pgina 36 de 141

Instrucciones de acceso a registros

delete_from myTable where ...; } Como se aprecia en el ejemplo, utilizando la instruccin delete_from en lugar de la whileselect, podemos economizar instrucciones de cdigo X++ y conseguir el mismo efecto.

JOBS
Un job es una porcin de cdigo la cual es ejecutada secuencialmente (desde arriba hasta abajo). Por defecto la siguiente lnea se encuentra en la parte superior de un nuevo job: Static void jobname (Args a) { } Los jobs que vers durante esta clase se parecern a este de aqu, excepto el nombre del job, el cual le dars t. Para aadir comentarios en el editor de texto se hace utilizando: //Este es un comentario de una sola lnea /* Para comentarios de ms de una lnea mejor utilizar esto*/ En ambos casos el texto cambiar de color a VERDE.

Pgina 37 de 141

Estndares para los mtodos de tablas

Estndares para los mtodos de las tablas


1. Introduccin
En un captulo anterior se indic que en Axapta podemos encontrar mtodos en todos los objetos de la aplicacin, y por lo tanto, en las tablas. stas disponen de una serie de mtodos que controlan su funcionalidad bsica, y que sern descritos en captulos posteriores. Adems de estos mtodos, el programador puede aadir aqullos que considere necesarios. Sin embargo, debe ajustarse a unos estndares de desarrollo. En Axapta, existen una serie de procedimientos de desarrollo estndar que son muy importantes. stos nos determinan la forma de trabajar, con el objetivo de facilitar la programacin, la comprensin del cdigo y la revisin del mismo por parte de personas distintas a las que han realizado el desarrollo inicial. Por eso es de vital importancia que siempre nos ajustemos lo ms posible a los estndares definidos. Un primer punto importante a sealar, es que no debemos escribir cdigo en X++ para solucionar problemas que pueden ser resueltos mediante las propiedades de los objetos, ya que es una prdida de tiempo y un esfuerzo de desarrollo intil. Por otro lado, el cdigo escrito en los mtodos de las tablas debe estar directamente relacionado con la tabla. Si no es as debemos plantearnos la posibilidad de escribir el cdigo en otras partes del sistema. Para aquellas tablas que tengan una clave primaria, SIEMPRE debemos crear los mtodos estndar que se describen en los siguientes apartados.

2.

Mtodo FIND
El mtodo find nos sirve para encontrar un registro determinado de una tabla, a partir de un valor del campo que sea la clave principal de la misma. Se trata de un mtodo esttico y que recibe los siguientes parmetros de entrada:

La clave de la tabla Un booleano opcional utilizado para indicar si se van a realizar una actualizacin del registro seleccionado El mtodo find de todas las tablas sigue la misma estructura. Veamos un ejemplo: Ejemplo static CustTable find(CustAccount boolean { CustTable custTable; ; custAccount, _forUpdate = false)

Pgina 38 de 141

Estndares para los mtodos de tablas

if (custAccount) { custTable.selectForUpdate(_forUpdate); select firstonly custTable index hint AccountIdx where custTable.accountNum == custAccount; } return custTable; } El hecho de que find sea un mtodo esttico nos facilita la tarea de buscar un registro de la tabla desde cualquier lugar del sistema, sin necesidad de tener una instancia de la tabla CustTable. La forma de ejecutar el mtodo sera por lo tanto la siguiente:

CustTable::find(customer) Donde customer sera una variable del tipo CustAccount que contendra el valor de la clave del registro que queremos buscar.

3.

Mtodo EXIST
El mtodo exist es un mtodo que nos indica si un registro determinado existe en la tabla, a partir de un valor del campo que sea la clave principal de la misma. Se trata de un mtodo esttico que tiene como parmetro de entrada el siguiente:

La clave de la tabla Ejemplo static boolean exist(CustAccount custAccount) { return (custAccount && CustTable::find(custAccount).recID != 0); } En el ejemplo se puede observar que se realiza una llamada al mtodo find. Resulta evidente que es mucho ms eficaz reutilizar el cdigo existente que reescribir la instruccin de seleccin.

4.

Mtodo TXTNOTEXIST
El mtodo TxtNotExist nos devuelve un texto esttico que utilizamos como mensaje de error. Ejemplo static str 80 txtNotExist()

Pgina 39 de 141

Estndares para los mtodos de tablas

{ return "@SYS9779"; } La etiqueta del ejemplo corresponde al texto La cuenta %1 no existe. Siempre que introduzcamos una cadena de texto en el cdigo deberemos utilizar etiquetas.

5.

Mtodo CHECKEXIST
El mtodo checkExist nos indica si un registro determinado existe en la tabla, a partir de un valor del campo que sea la clave principal de la misma. Si el registro no existe, devuelve un mensaje de error. Se trata de un mtodo esttico que recibe el siguiente parmetro de entrada:

La clave de la tabla Ejemplo static boolean checkExist(CustAccount custAccount) { if (custAccount && !CustTable::exist(custAccount))

return checkFailed(strfmt(CustTable::txtNotExist(),custAccount)); return true; } Como se observa en el ejemplo, el mtodo checkExist hace uso de los mtodos exist y txtNotExist descritos anteriormente. Tambin hace referencia a un metodo de la clase Global checkFailed

Pgina 40 de 141

Mtodos display y edit

Mtodos display y edit


Los trminos display y edit corresponden a modificadores de los mtodos, que dotan a stos de caractersticas especiales. Los mtodos de este tipo SIEMPRE deben tener un valor de retorno. En este captulo vamos a ver cmo y cundo se utilizan estos modificadores.

1.

Mtodos DISPLAY
El modificador display se utiliza para indicar que el valor de retorno del mtodo va a ser mostrado en un formulario o en un informe. Podemos utilizar este modificador en los mtodos de: Tablas Formularios Origen de datos de formularios Informes Diseo de informes

Siempre que sea posible, es aconsejable escribir los mtodos display en tablas, porque de esta forma puede utilizarse el mismo cdigo en varios formularios o informes.

1.1.

Definicin de un mtodo display


Para definir un mtodo display, es necesario escribir la palabra reservada display antes del tipo de retorno del mtodo. Por ejemplo: display Amount Amount() Existe un caso excepcional. Cuando definimos un mtodo display en el origen de datos de un formulario, se debe incluir dicho origen de datos como parmetro. Por ejemplo: display InventQty Accumulated(InventBudgetInvent Budget)

1.2.

Utilizacin de un mtodo display


Normalmente, los mtodos display se utilizan cuando queremos mostrar un campo calculado en un formulario o en un informe. No es recomendable, y de hecho no es estndar Axapta, almacenar en la base de datos valores calculados que cambian con el tiempo, como por ejemplo la deuda de un cliente. En estos casos el clculo debe realizarse en un mtodo display. Hay que tener en cuenta que al utilizar un mtodo display en un formulario, ste se ejecuta cada vez que el formulario se actualiza. Por lo tanto, el mtodo no debe realizar clculos que supongan un tiempo mayor al de una consulta directa a la base de datos.

Pgina 41 de 141

Mtodos display y edit

En los casos en que sea necesario realizar clculos costosos, es recomendable utilizar otro formulario para mostrar los valores calculados que se muestre al pulsar un botn. De este modo, slo se realizarn los clculos cuando el usuario lo solicite explcitamente. Veamos ahora cmo se utilizan los mtodos display. Una vez que se ha creado el mtodo, ste se utilizar en un control que se muestre en un formulario o en un informe. La forma de realizarlo es independiente del lugar donde se haya escrito el mtodo. Es necesario que el tipo de control y el tipo de retorno del mtodo sean idnticos. Esto significa que si, por ejemplo, tenemos en el formulario un control del tipo RealEdit, el mtodo display que estemos utilizando debe devolver un valor de tipo real. En un formulario, la propiedad DataSource indica donde est situado el mtodo, y la propiedad DataMethod indica el nombre del mtodo. Si la propiedad DataSource no tiene valor, el sistema asume que el mtodo ha sido definido en el formulario. En la siguiente figura se muestra la ventana de propiedades de un control de tipo real de un formulario:

En un informe, la propiedad DataMethod tambin indica el nombre del mtodo display. Si la propiedad Table no tiene valor, el sistema asume que el mtodo ha sido definido en el informe o en la clase de sistema ReportRun, donde tambin existen mtodos display. Por el contrario, cuando la propiedad Table tiene valor, el sistema busca el mtodo display en la tabla correspondiente. Si la propiedad ExtendedDataType tiene valor, el formato, el texto de ayuda, etc., se obtendrn del tipo de datos correspondiente. Si el mtodo display devuelve un vector, la propiedad ArrayIndex a 0 indica que todos los elementos del vector deben ser mostrados en el informe. Si, por ejemplo, ponemos la propiedad ArrayIndex a 2, solo el elemento nmero 2 del vector es mostrado.

Pgina 42 de 141

Mtodos display y edit

2.

Mtodos EDIT
El modificador edit es una extensin del modificador display, de forma que los controles que utilizan un mtodo edit, adems de mostrar un valor aceptan la entrada de datos por parte del usuario. Puede utilizarse en mtodos de los siguientes elementos: Tablas Formularios Orgenes de datos de los formularios

2.1.

Definicin de un mtodo edit


El formato de los parmetros en un mtodo edit es un poco diferente al de los mtodos display. Este es un ejemplo de un mtodo edit en una tabla: Edit FreeTxt TxtDefault(boolean Set, FreeTxt Txt) Utilizamos ambos parmetros cuando el mtodo est asociado a un control de un formulario. El parmetro booleano Set es verdadero si el usuario ha introducido algn valor en el control. El parmetro de texto Txt se utiliza para almacenar los valores que el usuario ha introducido en el control. El formato de parmetros para los mtodos edit que utilizamos en un formulario es idntico al utilizado en las tablas. Sin embargo, cuando utilizamos el mtodo edit como mtodo de un origen de datos de un formulario, dicho origen de datos debe aparecer tambin como parmetro, por ejemplo: edit Amount Settle(boolean set, CustTrans _custTrans, Amount u)

3.

Resumen del aspecto de los parmetros para los mtodos display y edit

Parmetros para display Mtodo en tabla Ninguno

Parmetros para edit

Boolean Set <Tipo de datos> valor Boolean Set <Tipo de datos> Ninguno Mtodo en formulario valor Boolean Set <Tipo de origen Mtodo en el origen de <Tipo de origen de datos> de datos> Origen de datos datos de un formulario Origen de datos <Tipo de datos> valor Mtodo en un informe Ninguno No aplicable No aplicable

Mtodo en el diseo de Ninguno un informe

Pgina 43 de 141

Mtodos display y edit

Mtodos bsicos en tablas


1. Definicin y modificacin de mtodos en tablas
Cuando se crea una nueva tabla en el Arbol de Objetos de la Aplicacin, MorphX automticamente crea una serie de mtodos para ella. Aadiendo cdigo X++ a estos mtodos podemos modificar el comportamiento predeterminado del sistema. Adems, podemos definir nuestros propios mtodos. Los mtodos de sistema y los definidos por el usuario comparten el mismo mbito, por lo tanto es posible aadir nuevos mtodos que pueden ser utilizados desde los mtodos definidos por el sistema. As como acceder a los mtodos de sistema desde cualquier nuevo mtodo. Es importante sealar que no podemos modificar el tipo de retorno, la lista de parmetros o el tipo de dichos parmetros en los mtodos definidos por el sistema, aunque podemos aadir parmetros adicionales siempre que declaremos un valor predeterminado para ellos.

2.

Mtodos de sistema
Los mtodos de sistema son ejecutados cuando se utiliza la tabla, por ejemplo, cuando introducimos, actualizamos o borramos datos. El cuerpo de estos mtodos inicialmente nicamente contiene una llamada al mtodo super(). En captulos posteriores se describir con ms detalle este mtodo. De momento nos basta con saber que corresponde al comportamiento predeterminado del sistema. Cuando se aade cdigo X++ a los mtodos definidos por el sistema, se sobrecarga este comportamiento. A continuacin se presentan la lista de mtodos de sistema de una tabla. En apartados posteriores se describirn con ms detalle los ms importantes. Mtodo Caption Se ejecuta cuando... se muestra la cabecera de un formulario. El texto se genera a partir de las propiedades de la tabla.

Clear

se borran los campos del registro actual (tienen valores NULL).

Delete

se elimina un registro.

HelpField

se muestra en la barra de estado el texto de ayuda de un campo, por ejemplo cuando pasamos al campo siguiente en un formulario.

InitValue

Inicializa los campos de un registro recin creado.

Pgina 44 de 141

Mtodos display y edit

Insert

se introduce un nuevo registro en la tabla.

Merge

se unen o combinan dos registros.

PostLoad

se carga un registro.

RenamePrimaryKey

se renombra la clave primaria de la tabla.

ReRead

se relee un registro.

ToolTipField

el puntero del ratn se sita en un campo de un formulario.

ToolTipRecord

se va a mostrar un consejo para el campo actual. El mtodo super() realiza una llamada a Caption.

Update

antes de modificar un registro existente.

ValidateDelete

se va a borrar un registro.

ValidateField

se abandona un campo, por ejemplo cuando saltamos al siguiente campo de un registro.

ValidateWrite

antes de escribir un registro en la base de datos.

2.1.

Mtodos de validacin en tablas


Los mtodos de validacin permiten al programador comprobar que se cumplen ciertas condiciones antes de que se ejecute una accin. En Axapta, se pueden programar mtodos de validacin a dos niveles: Tabla Origen de datos de un formulario En este captulo slo veremos los mtodos de validacin en tablas. Sin embargo, es importante conocer que los mtodos de validacin de las tablas se ejecutan siempre que se introducen o borran registros. Mientras que si la validacin se realiza en el formulario, slo funcionar cuando estemos trabajando con ese formulario.

Siempre que sea posible, la validacin de datos debe realizarse en la tabla.

Pgina 45 de 141

Mtodos display y edit

2.1.1.

Mtodos
Los mtodos de validacin en tablas son los siguientes:

a)

ValidateField Se ejecuta cuando movemos el cursor desde un campo del formulario a otro, es decir, cuando abandonamos un campo. Devuelve un dato de tipo booleano. Si el resultado es falso, el cursor permanecer en el campo. La llamada al mtodo super() comprueba las relaciones de validacin, es decir, relaciones en un campo donde la propiedad Validate tiene valor afirmativo. Por lo tanto, debemos respetar la tarea realizada por dicho mtodo super(). No deben codificarse validaciones que puedan realizarse con alguna propiedad. As, evitaremos escribir cdigo en el mtodo ValidateField si las condiciones pueden comprobarse con la propiedad Validate de una relacin.

b)

ValidateWrite Se ejecuta antes de insertar o actualizar un registro en la tabla. Devuelve un dato de tipo booleano. Si devuelve falso, el registro no se inserta o actualiza. La llamada al mtodo super() examina todos los campos para comprobar el valor de la propiedad Mandatory. Por lo tanto, debemos respetar la tarea realizada por dicho mtodo super(). Evitaremos introducir cdigo que compruebe si un campo tiene valor, siempre que podamos utilizar la propiedad Mandatory.

c)

ValidateDelete

No hay que olvidar, que a menudo tambin queremos comprobar ciertas condiciones antes de borrar un registro de una tabla. Para hacer esto, utilizamos el mtodo ValidateDelete(). ValidateDelete() se llama automticamente desde formularios y es utilizado para comprobar si el registro actual puede ser borrado. La llamada al mtodo super() comprueba si hay registros relacionados en tablas con DeleteActions del tipo Restricted. Si ese es el caso, el mtodo super() devuelve falso. Por lo tanto, debemos respetar la tarea realizada por dicho mtodo. Siempre que podamos utilizar un DeleteAction, evitaremos introducir cdigo en el mtodo ValidateDelete.

Pgina 46 de 141

Mtodos display y edit

2.1.2.

Estructura de los mtodos de validacin

Para mantener una buena estructura de programacin, es recomendable que el cdigo para las comprobaciones no se site directamente en estos mtodos de validacin. Es ms conveniente que creemos mtodos de comprobacin que sern llamados desde los mtodos de validacin anteriormente descritos. Ejemplo de mtodo de validacin Boolean validateWrite() { Boolean ret;

ret = checkSomething() && checkSomethingElse();

return ret; } Cuando no se cumple alguna de las condiciones, el mtodo de comprobacin debe realizar dos cosas: presentar al usuario un mensaje de error devolver el valor falso como resultado El mtodo CheckFailed(Mensaje de error) escribe la cadena de texto que recibe como parmetro en la ventana de informacin (Infolog) y devuelve el valor falso. Por lo tanto, mediante la utilizacin de este mtodo, conseguimos simultneamente los dos objetivos. Ejemplo de utilizacin de CheckFailed Boolean checkSomething () { Boolean ret;

if (!something) { ret = checkFailed(Something is wrong); } return ret; } Podramos utilizar la estructura anterior, pero existen casos en los que nos interesa comprobar la misma condicin Something, presente en el mtodo CheckSomething(), sin presentar ningn mensaje al usuario. En este caso necesitaramos un mtodo adicional, que comprobara la condicin pero que no mostrara ningn mensaje.

Pgina 47 de 141

Mtodos display y edit

Sin embargo, esto no sera muy eficiente, porque estaramos duplicando el cdigo de comprobacin, por lo tanto es ms recomendable crear un mtodo llamado Something(), al que podremos llamar cuando queramos, que se encargar de realizar dicha comprobacin. Deberemos, adems, cambiar el mtodo CheckSomething(), para que realice una llamada a este nuevo mtodo. El mtodo CheckSomething() lo utilizaremos nicamente cuando queramos mostrar un mensaje al usuario. Ejemplo de validacin completa Boolean something () { if (!something) { return false; } return true; }

Boolean checkSomething () { Boolean ret;

if (!something()) { ret = checkFailed(Something is wrong); } return ret; } Podemos considerar un estndar de nomenclatura de Axapta, la utilizacin del prefijo Check, en el nombre de todos aquellos mtodos que hagan una llamada al mtodo global CheckFailed(). De esta forma sabremos qu mtodos presentan mensajes en la ventana Infolog.

2.2.

Mtodos de sistema ms utilizados


A continuacin vamos a describir algunos de los mtodos ms utilizados en las tablas, que por su importancia merecen un tratamiento algo ms exhaustivo. Los ejemplos de los mtodos han sido obtenidos a partir de la tabla CustTable. a) InitValue

Pgina 48 de 141

Mtodos display y edit

El mtodo InitValue se ejecuta cuando aadimos un nuevo registro. Tambin es llamado automticamente desde los formularios. Por lo tanto, utilizaremos el mtodo para asignar valores iniciales o por defecto en un nuevo registro. Ejemplo void initValue() { CustParameters custParameters;

super(); this.languageId = CustParameters::languageId(); this.currency = CompanyInfo::find().currencyCode; } Hay que sealar que la llamada al mtodo super() no hace nada. b) Insert El mtodo Insert se ejecuta cuando se introduce un nuevo registro en la tabla. Es muy importante asegurar cualquier transaccin relacionada para asegurar la integridad de la base de datos. Las tcnicas de control de transacciones se vern en un captulo posterior. Ejemplo void insert() { this.setNameAlias(); super(); } Si el registro no puede ser insertado en la tabla, la llamada al mtodo super() devuelve un error. c) Update El mtodo Update se ejecuta antes de modificar un registro existente en la tabla. En este caso, tambin es muy importante controlar cualquier transaccin relacionada para asegurar la integridad de la base de datos. Ejemplo void update() { CustTable this_Orig = this.orig();

ttsbegin; this.setNameAlias();

Pgina 49 de 141

Mtodos display y edit

super(); this.setAccountOnVend(this_Orig); if (this_Orig.custGroup != this.custGroup) ForecastSales::setCustGroupId(this.accountNum, this_Orig.custGroup, this.custGroup); ttscommit; } En el ejemplo se utiliza el mtodo orig(). ste mtodo nos da acceso al registro antes de la actualizacin. d) Delete El mtodo delete se ejecuta cuando se elimina un registro. Es muy importante asegurar cualquier transaccin relacionada para asegurarnos la integridad de la base de datos. Supongamos dos tablas relacionadas llamadas TableA y TableB. Si en TableA hemos definido un DeleteAction de tipo cascada (Cascade) con respecto a TableB, cuando se borre un registro de TableA se borrarn los registros relacionados en TableB. Por razones de rendimiento, se debe evitar escribir cdigo en el mtodo Delete de dichas tablas relacionadas (en el ejemplo, TableB). Si no se ha aadido cdigo, los borrados en cascada pueden ser realizados rpidamente por el sistema gestor de base de datos utilizando directamente instrucciones de borrado SQL. Sin embargo, si aadimos cdigo en esas tablas (lo que puede ser necesario en algunas ocasiones), el sistema crea una instruccin while select y ejecuta el mtodo Delete en todas las tablas hijas relacionadas. De esta forma el rendimiento es menor que cuando utilizamos directamente instrucciones de borrado en SQL.

Pgina 50 de 141

Control de transacciones

Control de transacciones
1. Introduccin
Una transaccin es una unidad lgica de trabajo. Las transacciones son operaciones de todo o nada, que aseguran la integridad de los datos en las actualizaciones ms compelas. Consideremos el caso en el que queremos actualizar un grupo de registros. Si el sistema se estropea o el proceso es cancelado durante la operacin, algunos registros pueden haber sido actualizados y otros no. Si realizamos la actualizacin dentro de una transaccin, el sistema nos garantiza que o bien se actualiza completamente la totalidad de los registros o no se realiza ninguna operacin. Es decir, la actualizacin nicamente se consigue cuando la transaccin finaliza con xito. El uso de transacciones nos asegura, en caso de fallo del sistema, la recuperacin de los datos en su estado inicial, mediante un retroceso (rollback). Otro aspecto a tener en cuenta es que podra darse el caso de que dos procesos estuvieran accediendo a un mismo registro. Supongamos que el proceso A lee un registro y a continuacin un proceso B lee el mismo registro. En un instante posterior, el proceso A actualiza el registro y a continuacin el proceso B realiza la misma operacin. En este caso, los cambios realizados por el proceso A se perderan. La solucin a este problema es bloquear los registros o las tablas durante las transacciones de actualizacin (insert, update y delete). Esto podemos hacerlo mediante la sentencia select forUpdate.

2.

Instrucciones TTS
Las instrucciones tts se utilizan para marcar el inicio y el final de una transaccin.

2.1.

Instruccin TTSBEGIN
Utilizamos la sentencia ttsbegin para marcar el comienzo de una transaccin. Esto nos asegura la integridad de datos y garantiza que todas las actualizaciones realizadas hasta la finalizacin de la transaccin son consistentes, o por el contrario no se realiza ninguna. La instruccin ttsbegin no tiene ningn sentido si no tenemos una instruccin de final de transaccin.

2.2.

Instruccin TTSCOMMIT
Utilizamos la sentencia ttscommit para indicar que una transaccin ha finalizado con xito. Esta instruccin termina una transaccin y lleva a cabo todas las actualizaciones realizadas. MorphX garantiza que una transaccin terminada con la instruccin ttscommit ser realizada por completo.

Pgina 51 de 141

Control de transacciones

2.3.

Instruccin TTSABORT
La sentencia ttsabort nos permite desechar todos los cambios realizados en la transaccin actual de una manera explcita. Esto trae como consecuencia la finalizacin de la transaccin y la vuelta de la base de datos a la situacin inicial, justo antes de comenzar la transaccin. Por lo tanto, es como si no hubiramos realizado ningn cambio. Normalmente, utilizaremos esta sentencia si detectamos que el usuario quiere detener la tarea actual. El uso de la instruccin ttsabort, nos asegura que la base de datos ser consistente. A menudo, la mejor solucin es utilizar las sentencias de gestin de excepciones en lugar de utilizar la sentencia ttsabort.

2.4.

Anidamiento de transacciones
Las instrucciones entre las sentencias ttsbegin y ttscommit, pueden incluir uno o ms bloques de transacciones, es decir podemos anidar dichas transacciones. A continuacin presentamos un ejemplo: Ejemplo de transacciones anidadas ttsbegin; // Instrucciones ttsbegin; // Instrucciones ttscommit; // Instrucciones ttscommit; En estos casos es importante sealar, que la transaccin que realmente importa es la ms externa, es decir la que abrimos en primer lugar. De forma que nada se actualiza hasta que finaliza con xito la ltima instruccin ttscommit.

3.

Control de la integridad de transacciones


Axapta dispone de tcnicas internas de control que aseguran la integridad de las transacciones codificadas por los programadores de X++.

3.1.

Control de seleccin ForUpdate


Este tipo de control asegura que ningn registro puede ser actualizado o borrado si previamente no ha indicado explcitamente que se selecciona para ser actualizado. Un registro puede ser seleccionado para ser actualizado mediante la opcin forUpdate de la sentencia select o bien mediante el mtodo selectForUpdate de las tablas. Como ejemplo, Axapta generara un error ante la siguiente transaccin ya que el registro no se ha seleccionado para su actualizacin:

Pgina 52 de 141

Control de transacciones

ttsbegin; select * from myTable; myTable.myField = xyz; myTable.update(); ttscommit;

3.2.

Control a nivel de transaccin (tts)


Este control asegura que un registro nicamente puede ser actualizado o borrado dentro de la transaccin en la que ha sido seleccionado para actualizacin. El siguiente ejemplo dara lugar a un error dado que la seleccin y la actualizacin se realizan en transacciones diferentes: ttsbegin; select forUpdate * from myTable; myTable.myField = xyz; ttscommit; ttsbegin; myTable.update();

Pgina 53 de 141

Herramientas de desarrollo

Herramientas de desarrollo
1. El editor
El editor de cdigo se puede abrir pulsando dos veces con el ratn sobre el nombre de un mtodo, o bien seleccionando la opcin Edit del men contextual de dicho mtodo.

Icon

Description Crea un Nuevo mtodo o Job. Puedes tener varios mtodos/jobs abiertos al mismo tiempo en el editor. Cada mtodo tiene su propia pestaa con el nombre del Job como ttulo. Salva el cdigo. Si cierras el Job, el sistema te preguntar si quieres guardar los cambios. Ejecuta el Job. El Job es tambin compilado. Un Job con un error de compilacin no funcionar. Sita un punto de interrupcin que el Debugger reconoce. Compila el cdigo. El compilador chequea los errores que hay ahora en el cdigo. La ventana de mensaje nos mostrar si el error es, por ejemplo, de sintaxis, coherencia, ... Propiedades de los mtodos. Te da el perfil de parmetros de un mtodo. Muestra el editor de etiquetas. Esto te da el texto de la etiqueta de la etiqueta que est seleccionada. Este icono te dar una lista completa de todas las etiquetas disponibles. Ejecuta un script, por Ejemplo, para transformar una parte seleccionada del cdigo en un comentario., o para insertar una cabecera en el Job incluyendo informacin sobre cuando y por quin ha sido editado el Job. Ayuda. Mira entre otras cosas una lista de teclas de acceso rpido. Hay tecla de acceso rpido para listas por ejemplo, tablas clases, o Enums.

Pgina 54 de 141

Herramientas de desarrollo

Click en el botn derecho del ratn en cualquier lugar de la ventana del editor para recibir este men. Adems de repetir varias funciones en la barra de estado del editor, el men incluye un nmero de funciones. Usa este men para mostrar, por ejemplo, tablas, clases y Enums cuando ests escribiendo cdigo en el editor. Usando las teclas de acceso rpido. (como las descritas arriba) para acceder a la misma lista a travs del teclado.

El nombre del mtodo seleccionado se muestra dentro de una solapa. El editor facilita el trabajo con varios mtodos a la vez, ya que cada vez que editamos un mtodo de la misma clase, se crea una nueva solapa en la misma ventana. Por otro lado, permite utilizar las funciones de edicin estndar de Windows tales como copiar, cortar y pegar. La opcin IntelliSense resulta de gran ayuda al desarrollador, ya que cada vez que ste introduce el nombre de un objeto, le muestra su lista de miembros (variables y mtodos). De este modo, el programador no necesita recordarlos. Esta opcin est activa por defecto, pero puede desactivarse desde la ventana de opciones de desarrollo. Esta lista se presenta tambin, si el desarrollador marca el objeto con el ratn y selecciona la opcin Buscar propiedades/mtodos del men contextual o bien pulsa el botn de la barra de herramientas del editor. El resultado se muestra en la figura 1.

Figura 1. Opcin Buscar propiedades/mtodos.

Pgina 55 de 141

Herramientas de desarrollo

Si situamos el cursor sobre un objeto que no dispone de miembros, el sistema muestra un mensaje de ayuda emergente con informacin sobre el tipo de objeto, tal y como muestra la figura 2.

Figura 2. Opcin Buscar propiedades/mtodos.

Esta informacin tambin puede obtenerse mediante la combinacin de teclas CTRL+SPACE. El men contextual nos ofrece otras opciones de bsqueda, como Buscar etiqueta/texto que abre el generador de etiquetas. Este mismo resultado se obtiene pulsando sobre el botn de la barra de herramientas del editor.

Por ltimo, la opcin Buscar definicin ejecutada sobre un mtodo, abre este mtodo en una nueva ventana del editor. El editor tambin nos ofrece la posibilidad de utilizar la tecla F1 para obtener ayuda sensible al contexto. Si marcamos con el ratn un elemento cuya informacin de ayuda se encuentra en la Documentacin de sistema o bien en la Documentacin de la aplicacin y pulsamos F1, se mostrar esta ayuda. As, por ejemplo si marcamos una variable perteneciente a una clase de sistema y pulsamos F1, obtendremos ayuda acerca de esta clase. Si F1 se pulsa en un elemento del que no se dispone informacin, obtendremos ayuda acerca del uso del editor de texto. El men contextual nos ofrece otras utilidades como las listas de objetos. As, encontramos las siguientes opciones: Enumerar tablas Enumerar clases Enumerar tipos

Pgina 56 de 141

Herramientas de desarrollo

Listar enumeraciones Enumerar palabras reservadas Enumerar funciones incorporadas

Figura 3. Opcin Listar enumeraciones.

Cada una de estas opciones muestra la lista de objetos correspondiente, de la cual podemos seleccionar el que nos interese. En la figura siguiente podemos ver el resultado de seleccionar la opcin Listar enumeraciones. Como vemos, tenemos acceso a los elementos del enumerado seleccionado. Para salir del editor podemos pulsar la tecla ESC. Si hemos realizado cambios, el sistema preguntar si queremos guardar dichos cambios.

2.

El generador de etiquetas
Cuando tengamos la necesidad de introducir algn texto en nuestro cdigo lo haremos utilizando una etiqueta. Las etiquetas en Axapta son uno de los elementos fundamentales para asegurarnos que las aplicaciones realizadas sern multi-lenguaje, es decir, podremos elegir el idioma en el que queremos que aparezcan nuestros formularios, informes, cuadros de dilogo, etc. Para la creacin de etiquetas disponemos en Axapta de un generador de etiquetas que va a facilitar nuestro trabajo. Cuando pulsamos con el ratn sobre el botn , nos aparece esta herramienta, que nos permite buscar, crear e insertar etiquetas. Como hemos comentado en el apartado anterior, el generador de herramientas tambin se puede abrir mediante la opcin Buscar etiqueta/texto del men contextual.

Pgina 57 de 141

Herramientas de desarrollo

Figura 4. El generador de etiquetas.

La lista desplegable Idioma seleccionado, muestra el lenguaje que se seleccion al poner en funcionamiento la aplicacin. Cuando comenzamos la bsqueda de una cadena de texto determinada, este parmetro determina el fichero de etiquetas en el cual se realizar la bsqueda. El cuadro de texto Bsqueda de etiqueta, nos permite introducir la cadena de texto que queramos buscar en el fichero de etiquetas. La bsqueda encuentra todas las instancias de la cadena de texto. El botn de comando Buscar ahora, comienza la bsqueda de la cadena de texto que se haya introducido en el cuadro de texto que acabamos de describir. La lista en el cuadro de dilogo muestra el resultado de la bsqueda de la cadena de texto. Se nos muestran los nombres de todas las etiquetas, por las que nos podemos desplazar utilizando los botones Siguiente y Anterior. La casilla de verificacin Mostrar todos los idiomas, muestra las traducciones de la etiqueta actual en todos los lenguajes disponibles en nuestra instalacin de Axapta. La lista desplegable Archivo de etiquetas, nos muestra los caracteres que identifican un archivo de etiquetas. El nombre de los archivos de etiquetas se compone del siguiente modo: Ax<identificador><idioma>.ald, donde ald es el acrnimo de application label data (datos de etiquetas de la aplicacin). En la aplicacin estndar, el identificador del archivo es SYS. En nuestros desarrollos podremos definir un archivo de etiquetas para el nivel en el que estemos trabajando o bien podemos utilizar otras tcnicas, tales como crear un archivo por cada aplicacin desarrollada.

Pgina 58 de 141

Herramientas de desarrollo

3.

El depurador
El depurador es una herramienta de desarrollo presente en el entorno MorphX, como sucede en la mayora de entornos de programacin. La utilizacin del depurador va a ser muy til en tareas relacionadas con la programacin de aplicaciones, como la deteccin de errores, optimizacin de cdigo, etc. Con el depurador podemos realizar distintas operaciones, que pueden ser ejecutadas desde los botones de la barra de herramientas o bien mediante una combinacin de teclas. Estas operaciones son las siguientes: Ejecutar cdigo Ejecutar paso a paso las lneas de cdigo Introducir puntos de ruptura (breakpoints) Abrir una ventana de variables, donde se muestra una lnea para cada variable con su nombre, tipo, mbito y valor Ver la pila de llamadas Ver el estado del sistema Mostrar los nmeros de lneas en el cdigo Cuando elegimos la opcin de ejecutar nuestro cdigo con informacin de depuracin, las lneas de cdigo se muestran en la ventana del depurador. Para poder poner en marcha el depurador de cdigo debemos introducir un punto de ruptura o breakpoint. Podemos introducir un punto de ruptura directamente desde el editor de cdigo situando el cursor en la lnea en la que queremos que se detenga la ejecucin y pulsando con el ratn en el botn hacerlo apretando la tecla F9. de la barra de herramientas. Tambin podemos

Cuando ejecutemos el cdigo, la ejecucin se detendr en el punto de ruptura y se abrir el depurador. La siguiente figura muestra la apariencia del depurador:

Figura 5. El depurador.

Pgina 59 de 141

Herramientas de desarrollo

En la ventana de variables podemos ver cmo cambia el valor de las variables a medida que vamos ejecutando el cdigo paso a paso. Tambin podemos poner una o ms variables a un valor especfico, introduciendo ste en la columna Valor.

Figura 6. La ventana de variables del depurador.

Podemos activar la ventana de variables pulsando sobre el botn herramientas del depurador.

de la barra de

Cuando una lnea en la ventana de variables contiene un objeto compuesto, podemos situar el cursor en esa lnea y apretar la tecla ENTER. Se abrir una segunda ventana que mostrar el valor actual de cada uno de los elementos de dicho objeto.

Figura 7. Ventana de elementos de un objeto compuesto.

Pgina 60 de 141

Programacin de formularios

4.

Seguimientos o trazas

Si se quiere realizar una traza del programa en ejecucin necesitas activar las trazas. Para hacer esto debes ir al men de herramientas, seleccionar opciones, y una vez dentro de opciones marcar la pestaa de desarrollo., Aqu ves un grupo de traza (Seguimiento), en el que hay 4 opciones: Seguimiento de la base de datos. Seguimiento de los mtodos. Seguimiento de cliente/servidor. Seguimiento ActiveX. Cuando seleccionas un seguimiento de los mtodos una pantalla aparecer tan pronto se active uno de los controloes a los que estoy siguiendo. Nota: Hay que darse cuenta de que si seleccionas seguimiento de mtodos conseguirs mucha informacin muy rpido porque Axapta muestra todos los mtodos que son llamados, como OnMouseMove o OnMouseLeave.

Programacin de formularios
1. Introduccin
Como ya hemos comentado, podemos introducir cdigo en lenguaje X++ en muchas partes del sistema. Los formularios no son una excepcin. Existen distintos mbitos en los formularios donde podemos aadir cdigo. Estos mbitos son los siguientes: Formulario propiamente dicho Origen de datos del formulario Controles del formulario Dependiendo de la funcionalidad que queramos implementar, escribiremos el cdigo en un mbito o en otro. No obstante, normalmente, se siguen las siguientes reglas: Codificamos en los mtodos del propio formulario, cuando queremos controlar la funcionalidad general del mismo. Codificamos en los mtodos del origen de datos, cuando queremos controlar la funcionalidad de los datos que aparecen en el formulario.

Pgina 61 de 141

Programacin de formularios

Codificamos en los controles, cuando queremos controlar la funcionalidad de alguno de los controles o elementos especficos que aparecen en el formulario.

Se debe tener en cuenta que el cdigo que se introduce en un formulario ser accesible nicamente desde el formulario. Cualquier funcionalidad que deba ser accesible desde otro elemento, debe codificarse fuera del formulario. La funcionalidad relacionada con los datos se codificar en la tabla siempre que sea posible. Si se trata de otro tipo de funcionalidad, puede implementarse una clase para ello.

2.

Variables del sistema


Anteriormente se dijo que todas las variables deben ser declaradas antes de poder ser utilizadas. Sin embargo, cuando trabajamos con los formularios, algunas variables son declaradas implcitamente por el sistema. Adems de estas variables, es conveniente recordar que en cualquier momento, la variable this nos da acceso al elemento al que pertenece el mtodo que estamos modificando. A continuacin se describen las variables de sistema de los formularios y los elementos a los que dan acceso: a) Formulario

Se trata de una variable de tipo FormRun, que recibe el nombre de element y que referencia al objeto formulario. Nos permite acceder a los mtodos definidos a nivel de formulario. La variable element se utiliza normalmente en asignaciones como la que mostramos a continuacin: Tb. Existe la variable form notifyDate = element.design().control(Control::NotifyDate); b) Tabla

Por cada uno de los orgenes de datos del formulario, disponemos de una variable llamada como stos, que nos referencia la tabla que utilizamos en dicho origen de datos. Por ejemplo, suponiendo que el origen de datos del formulario se llamara DatosFormulario, tendramos una variable con ese nombre que hara referencia a la tabla. En realidad, en un momento dado esta variable nos da acceso al registro activo de la tabla, de manera que podremos: 1. Llamar a un mtodo definido en la tabla. Por ejemplo: DatosFormulario.setDefault(ReadWrite::Write); 2. Hacer referencia a los campos individuales de la tabla. Por ejemplo: number = DatosFormulario.accountNo; c) Origen de datos

Pgina 62 de 141

Programacin de formularios

Tendremos tambin una variable llamada como el origen de datos del formulario con el sufijo _DS para hacer referencia a las propiedades y los mtodos de dicho origen de datos. Por ejemplo, en el caso de que nuestro origen de datos se llamara DatosFormulario, tendramos una variable llamada DatosFormulario_DS. Se trata de una variable de tipo FormDataSource que nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: DatosFormulario_DS.reSearch(); d) Consulta Existen dos variables que nos permiten acceder a la consulta de un formulario: Una variable de tipo Query llamada como el origen de datos del formulario con el sufijo _Q para hacer referencia a las propiedades y los mtodos de la consulta (query). Por ejemplo, en nuestro caso, tendramos una variable llamada DatosFormulario_Q. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: DatosFormulario_Q.levelNo(1); Una variable de tipo QueryRun llamada como el origen de datos del formulario con el sufijo _QR para hacer referencia a las propiedades y los mtodos de una instancia en ejecucin de la consulta de dicho origen de datos (queryRun). Por ejemplo, en nuestro caso, tendramos una variable llamada DatosFormulario_QR. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: DatosFormulario_QR.getNo(1); Es importante sealar que en versiones anteriores de Axapta, no existan las variables declaradas implcitamente para la consulta (_Q) y para la instancia en ejecucin de la consulta (_QR). Esto hace que nos podamos encontrar en muchos mtodos todava la forma tradicional de acceder a ellas desde cdigo. Para acceder a una consulta, debamos hacer una declaracin de variable, tras la cual podamos utilizar la variable declarada para acceder a los mtodos de dicha consulta. Por ejemplo, dentro de un origen de datos podramos acceder a su consulta de la siguiente forma: Ejemplo de declaracin de una consulta Query ; q = this.query(); q.levelNo(1); Para acceder a una instancia en ejecucin de una consulta, tambin debamos hacer una declaracin de variable. Siguiendo con el mismo ejemplo lo haramos de la forma siguiente: Ejemplo de declaracin de instancia en ejecucin de una consulta QueryRun ; qr = this.queryRun(); qr; q;

Pgina 63 de 141

Programacin de formularios

qr.getNo(1); En ambos casos la variable this hara referencia al objeto en ejecucin en ese momento, es decir, al origen de datos.

Siempre es ms aconsejable utilizar las variables implcitas declaradas por el sistema en lugar de definir nuevas variables, ya que de esta forma evitamos que existan variables iguales duplicadas en memoria.

3.

Mtodos del formulario


Cuando creamos un nuevo formulario el sistema genera automticamente un nodo de mtodos. Adems de modificar los mtodos creados por el sistema, el desarrollador puede aadir nuevos mtodos con el propsito de aadir funcionalidad lgica al formulario.

Es interesante recordar, que siempre que sea posible, se debe introducir el cdigo en la tabla de la que se obtienen los datos para el formulario. Los mtodos escritos en la tabla son accesibles desde cualquier formulario que utilice dicha tabla. En trminos de reutilizacin y herencia, aadir cdigo en los mtodos de un formulario es menos eficiente que introducirlo directamente en la tabla.

3.1.

Mtodos de sistema
El nodo contiene lo que se llaman mtodos virtuales, que son mtodos implementados en MorphX, pero que pueden ser sobrecargados para cambiar el comportamiento por defecto de los formularios. En estos mtodos la funcin llamada super() activa la ejecucin del mtodo implementado por MorphX.

3.1.1.

Lista de mtodos
Los formularios en MorphX tienen los siguientes mtodos de sistema:

Mtodo CanClose

Se ejecuta cuando... se cierra un formulario. Utilizaremos este mtodo, para aadir nuestras propias comprobaciones a las que realiza el sistema cuando cerramos un formulario. se cierra un formulario. Dependiendo del estado en el cual cierre el formulario, el mtodo Close se activa desde CloseCancel o desde CloseOK. el usuario pulsa con el ratn sobre el botn cancelar o cuando pulsamos le techa ESC. Cuando cerramos un formulario mediante el mtodo CloseCancel, no grabamos las modificaciones. el usuario pulsa con el ratn el botn Aceptar.

Close

CloseCancel

CloseOK

Pgina 64 de 141

Programacin de formularios

DoApply Finalize

el usuario cierra un formulario modal. se cierra el formulario. El objetivo de este mtodo es destruir el objeto y liberar la memoria. nos movemos al primer campo de un formulario. abrimos el formulario. nos movemos al ltimo campo de un formulario. nos movemos al siguiente campo dentro de un formulario. nos movemos al siguiente grupo de campos dentro de un formulario. nos movemos al campo anterior dentro de un formulario. nos movemos al grupo de campos anterior dentro de un formulario. abrimos el formulario, inmediatamente despus del mtodo Init, para mostrar el formulario. el usuario realiza alguna tarea en el formulario, como por ejemplo: utilizar la barra de herramientas, el men o el teclado.

FirstField Init LastField NextField NextGroup

PrevField PrevGroup Run

Task

3.1.2.

Mtodos principales y su funcin

A continuacin vamos a describir algunos de los mtodos ms utilizados en los formularios, que por su importancia merecen un tratamiento algo ms exhaustivo. a) Mtodo ClassDeclaration En este mtodo se definen las variables globales del formulario. Es decir, aqullas cuyo mbito es el formulario en su totalidad y, por lo tanto, pueden ser utilizadas en cualquier mtodo del formulario, de los orgenes de datos o de los controles. Como ejemplo, veamos el mtodo ClassDeclaration del formulario CustTable. Ejemplo de mtodo ClassDeclaration class FormRun extends ObjectRun { NumberSeq CustAccount FormStringControl FormStringControl } b) Mtodo Init numberSeq; numAllocated; contactPerson; contactPersonId;

Pgina 65 de 141

Programacin de formularios

Se ejecuta cuando abrimos el formulario. Se utiliza, bsicamente, para la inicializacin de variables. Debemos realizar una llamada al mtodo super(), ya que ste es el encargado de crear una instancia en ejecucin del formulario. Crea tambin el origen de datos, mediante una llamada al mtodo Init del origen de datos. Antes de la llamada al mtodo super(), podemos modificar el formulario mediante los mtodos de la clase FormBuild. Tras el mtodo super() y una vez creado el formulario, podemos inicializar variables. Como ejemplo, tenemos el mtodo Init del formulario CustTable. Ejemplo de mtodo Init void init() { super(); contactPersonId = element.control(control::ContactPersonId); TaxVATNumTable::enableLookupVatNum(vatNum); } c) Mtodo Run Se ejecuta cuando abrimos un formulario, inmediatamente despus del mtodo Init. La llamada al mtodo super() hace que la ventana aparezca en la pantalla, y realiza una bsqueda en la base de datos para obtener los datos que deben mostrarse en el formulario. La consulta la realiza activando el mtodo ExecuteQuery() del origen de datos. d) Mtodo Close Se ejecuta cuando cerramos un formulario. La llamada a super() cierra la ventana del formulario, realiza las actualizaciones en la base de datos y activa el indicador booleano Closed. Dependiendo del estado en el cual cierre el formulario, el mtodo Close se activa desde CloseCancel o desde CloseOK. Como ejemplo, tenemos el mtodo Close del formulario CustTable. Ejemplo de mtodo Close void close() { if (!custTable.recId && numberSeq) numberSeq.abort(); super(); }

Pgina 66 de 141

Programacin de formularios

3.2.

Acceso a los controles desde el cdigo


Desde cualquier mtodo podemos acceder a las propiedades y mtodos de los controles del formulario. Para ello, necesitamos tener una referencia al control, que se puede obtener de dos formas: Mediante la propiedad Autodeclaration de los controles Mediante mtodos de las clases de sistema Todos los controles de un formulario tienen una propiedad llamada Autodeclaration. Por defecto, esta propiedad est desactivada, pero si la activamos, el sistema crea de modo automtico una variable con el mismo nombre del control que nos da acceso a todas sus propiedades y mtodos. Esta propiedad es una novedad de la versin 2.0 de Axapta, por lo tanto nos encontraremos que en muchas ocasiones no se hace uso de ella y se utilizan las clases de sistema para hacer referencia a los controles. Sin embargo, es recomendable hacer uso de las propiedades de los elementos de la aplicacin, ya que nos ahorran cdigo innecesario. Para crear una referencia a un control de un formulario mediante el segundo mtodo debemos seguir los siguientes pasos: 1. Declarar una variable de tipo control 2. Inicializar la referencia La variable de referencia debe ser declarada en el mtodo ClassDeclaration del formulario. El tipo de datos de la variable depende del tipo de control al que queramos hacer referencia. Por ejemplo, para hacer referencia a un campo de texto, deberemos crear una variable de tipo FormStringControl, para hacer referencia a un botn, la variable ser de tipo FormButtonControl, etc. Estas clases pueden encontrarse en la documentacin del sistema en el rbol de Objetos de la Aplicacin. Ejemplo FormButtonControl button;

La inicializacin de las variables debe hacerse en el mtodo Init, haciendo uso de los mtodos de la clase de sistema FormRun. Suponiendo que en nuestro formulario tuviramos un control de tipo botn llamado ButtonName, tendramos el siguiente ejemplo, donde se asignara dicho botn a la variable button: Ejemplo button = element.design().control(Control::ButtonName); Una vez inicializada la variable, podemos cambiar las propiedades del control en cualquier momento utilizando sus propios mtodos. A continuacin mostramos un ejemplo de esto: Ejemplo button.enabled(false); A continuacin presentamos un ejemplo, donde podemos observar la asignacin de controles de un formulario a variables previamente declaradas.

Pgina 67 de 141

Programacin de formularios

Ejemplo de declaracin de controles class FormRun extends ObjectRun { FormCheckBoxControl FormStringControl FormDateControl } includeAll; interestNote; interestDate;

void init() { super(); includeAll = element.control(control::ShowOpen); interestNote = element.control(control::InterestNote); interestDate = element.control(control::InterestDate); } Por otra parte, si sabemos que no vamos a necesitar hacer referencia al control ms de una vez, podemos eliminar la variable y cambiar la propiedad de dicho control en una sola sentencia. Ejemplo element.design().control(Control::ButtonName).enabled(false);

4.

Mtodos del origen de datos


Cuando creamos un nuevo formulario debemos definir un origen de datos, que nos da acceso a la informacin almacenada en la base de datos. Al definir un origen de datos, se crea automticamente un nodo de mtodos.

4.1.
4.1.1.

Mtodos de sistema
Lista de mtodos
Los orgenes de datos en los formularios tienen los siguientes mtodos de sistema: Mtodo Active Create Delete ExecuteQuery Se ejecuta cuando... el usuario cambia de registro activo. el usuario crea un nuevo registro. el usuario borra un registro. abrimos el formulario y el sistema accede a la base de datos para

Pgina 68 de 141

Programacin de formularios

recuperar la informacin que se va a mostrar al usuario. FindRecord FindValue se ejecuta desde el mtodo FindValue. el usuario pulsa con el ratn sobre el comando Buscar (Find) en el men contextual. nos movemos al primer registro. se abre el formulario. se crea un nuevo registro. Su propsito es dar valores iniciales al nuevo registro. nos movemos al ltimo registro. el usuario cambia de registro en un formulario que tiene su origen de datos enlazado con otro origen de datos. nos movemos al siguiente registro. nos movemos al registro anterior. el usuario activa el comando Imprimir (Print) en el men Archivo. el usuario activa el comando Filtrar (Filter). Refresca el contenido del registro activo sin leerlo desde el disco. Este mtodo no lo activa automticamente el sistema. el usuario pulsa con el ratn sobre el comando Eliminar filtro (Remove filter) en el men contextual. Se refresca el contenido del registro activo leyendolo de la base de datos. Este mtodo no lo activa automticamente el sistema. Vuelve a ejecutar el mtodo ExecuteQuery con la excepcin de que se preserva el filtro, el orden de los registros, etc. Este mtodo no lo activa automticamente el sistema. vamos a borrar un registro. vamos a actualizar un registro o escribir un nuevo registro. el usuario introduce un nuevo registro o actualiza uno existente.

First Init InitValue

Last LinkActive

Next Prev Print Prompt Refresh

RemoveFilter

Reread

Research

ValidateDelete ValidateWrite Write

4.1.2.

Mtodos de validacin

Como hemos visto en la lista anterior, los orgenes de datos tienen sus propios mtodos de validacin. Estos mtodos son los siguientes: a) ValidateDelete Este mtodo se ejecuta justo antes de que un registro vaya a ser borrado. La llamada al mtodo super() invoca al mtodo ValidateDelete de la tabla asociada.

Pgina 69 de 141

Programacin de formularios

Utilizamos este mtodo cuando queremos aadir nuestras propias comprobaciones de validacin antes del borrado de los registros de la base de datos. b) ValidateWrite Este mtodo se ejecuta justo antes de que un registro vaya a ser escrito o actualizado. La llamada al mtodo super() invoca al mtodo ValidateWrite de la tabla asociada. Tambin utilizamos este mtodo cuando queremos aadir nuestras propias comprobaciones de validacin antes de la actualizacin o escritura de los registros en la base de datos. Como podemos apreciar, existe un paralelismo entre los mtodos de la tabla y los mtodos del origen de datos de un formulario. En realidad, los mtodos de validacin del origen de datos llaman a los de la tabla asociada. A partir de esto podemos llegar a la conclusin de que introduciremos los mtodos de validacin en un sitio o en otro dependiendo de nuestro objetivo. Supongamos que tenemos varios formularios que trabajan con los mismos datos. Cada uno de ellos tendr su propio origen de datos, pero todos esos orgenes de datos tendrn asociada la misma tabla. Si nosotros queremos validar el borrado o la escritura de los registros en todos los formularios, ser ms conveniente hacer la comprobacin directamente en los mtodos de validacin de la tabla, ya que solo tendramos que escribir el cdigo una vez. Esta validacin sera efectiva en todos los orgenes de datos que tuvieran dicha tabla asociada. Por el contrario, vamos a considerar que en un formulario especfico necesitamos realizar una validacin especial cuando queremos insertar un registro. Esta comprobacin ser ms conveniente hacerla sobre los mtodos de validacin del origen de datos de dicho formulario. No sera vlido hacerlo en los mtodos de la tabla, porque de esta forma estaramos forzando a todos los formularios a realizar esta validacin. A continuacin, vamos a ver cual es la secuencia de ejecucin de mtodos cuando intentamos escribir o actualizar un registro desde un formulario. Podemos verlo de manera grfica en el siguiente esquema:

Figura 8. Escritura de un registro. Secuencia de ejecucin de mtodos.

La secuencia de ejecucin sera la siguiente:

Pgina 70 de 141

Programacin de formularios

1.

Se ejecutara el mtodo ValidateWrite del origen de datos del formulario. Este a su vez llamara al mtodo ValidateWrite de la tabla asociada. Se ejecutara le mtodo Write del origen de datos del formulario. Se llamara al mtodo Insert o al mtodo Update de la tabla asociada al formulario, dependiendo de si la operacin a realizar en una insercin o una actualizacin de registro.

2. 3.

En la programacin de los mtodos de validacin de los orgenes de datos debemos seguir la misma estructura estndar que se sigue en los mtodos de validacin de las tablas.

4.1.3.

Mtodos principales y su funcin

A continuacin vamos a describir algunos de los mtodos ms utilizados en los orgenes de datos de los formularios, que por su importancia merecen un tratamiento algo ms exhaustivo. a) Mtodo Init Se ejecuta cuando abrimos un formulario. La llamada al mtodo super() crea la consulta para cargar los datos en el formulario. Tras esta llamada deben aadirse, en caso de que sea necesario, las sentencias de modificacin de la consulta. Como ejemplo, presentamos el mtodo Init del origen de datos del formulario CustTrans. Ejemplo de mtodo Init void init() { super(); dataSource = this.query().dataSourceNo(1); criteriaOpen = dataSource.addRange(fieldnum(CustTrans,open)); } b) Mtodo ExecuteQuery El mtodo ExecuteQuery se ejecuta cuando abrimos un formulario para ver sus datos. La llamada al mtodo super() ejecuta la consulta generada por el mtodo Init y muestra los registros. Si deseamos modificar los criterios de seleccin, debemos insertar las sentencias correspondientes antes de la llamada a super(). Como ejemplo, presentamos el mtodo ExecuteQuery del origen de datos del formulario CustTrans. Ejemplo de mtodo ExecuteQuery

Pgina 71 de 141

Programacin de formularios

void executeQuery() { switch (includeAll.value()) { case (1) : { criteriaOpen.value('1'); break; } case (0) : { criteriaOpen.value('0..1'); break; } } super(); } En este ejemplo, vemos que el mtodo puede servirnos para establecer dos criterios distintos de seleccin en la consulta antes de la llamada al mtodo super(). c) Mtodo Active Se ejecuta cada vez que cambia el registro activo. Esto sucede cuando pasamos de un registro a otro y tambin cuando pasamos de un formulario a otro. La llamada a super() hace que el nuevo registro pase a ser el registro actual. Como ejemplo, presentamos el mtodo Active del origen de datos del formulario Unit. Ejemplo de mtodo Active int active() { int ret; ; ret = super(); Unit_Unit.allowEdit(!Unit.recId); return ret; } d) Mtodo LinkActive

Pgina 72 de 141

Programacin de formularios

El mtodo LinkActive se ejecuta cuando el usuario cambia de registro en un formulario que tiene su origen de datos enlazado con otro origen de datos. Este mtodo solo es utilizado cuando se ha establecido un enlace entre dos orgenes de datos, poniendo la propiedad LinkType a valor Yes en el origen de datos. La llamada al mtodo super() activa el mtodo ExecuteQuery del origen de datos enlazado con el origen de datos principal. Como ejemplo, presentamos el mtodo LinkActive del origen de datos SalesLine del formulario SalesTable. Ejemplo de mtodo LinkActive void linkActive() { super(); if (!salesLine) element.setCaptionText(); } e) Mtodo Reread La llamada al mtodo super() vuelve a leer el registro actual de la base de datos. El sistema no activa este mtodo de forma automtica. f) Mtodo Research La llamada al mtodo super() refresca la recuperacin de registros de la base de datos, definida por la consulta que se genera automticamente en el mtodo Init. Corresponde a una llamada al mtodo ExecuteQuery con la excepcin de que se mantienen ciertas cosas, como los filtros, el orden de los registros, etc. El sistema no activa este mtodo de forma automtica. Para comprender bien el funcionamiento del mtodo Research, vamos a ver las diferencias existentes entre dicho mtodo y el mtodo ExecuteQuery. Si queremos refrescar el contenido del formulario con los registros que han sido insertados desde un mtodo al cual hemos llamado, debemos utilizar el mtodo Research. Por el contrario, si queremos cambiar la consulta para mostrar otros registros, quizs basados en un filtro modificado, debemos utilizar el mtodo ExecuteQuery. g) Mtodo Refresh La llamada al mtodo super() actualiza la pantalla, refrescando el contenido del registro activo sin leerlo desde el disco. El sistema no activa este mtodo de forma automtica. Nosotros podemos utilizarlo, por ejemplo, si necesitamos actualizar los datos dentro de una operacin ms compleja.

Pgina 73 de 141

Programacin de formularios

h)

Mtodo Write El mtodo Write se ejecuta cuando el usuario introduce un nuevo registro o actualiza uno ya existente. Este mtodo es el equivalente a los mtodos Insert y Update de las tablas, realizando una u otra operacin dependiendo de que exista ya el registro sobre el que vamos a escribir o no. La llamada al mtodo super() activa el mtodo ValidateWrite, y en el caso de que ste devuelva verdadero, gestiona la accin de escritura sobre la base de datos. Como ejemplo, presentamos el mtodo Write del origen de datos del formulario LedgerJournalTable. Ejemplo de mtodo Write void write() { super(); if (newJournalNum) { ledgerJournal.usedVoucher(); ledgerJournal = null; newJournalNum = false; } }

i)

Mtodo Delete El mtodo Delete se ejecuta cuando el usuario borra un registro en el origen de datos. La llamada al mtodo super() activa el mtodo ValidateDelete y en el caso de que ste devuelva verdadero, gestiona la accin de borrado sobre la base de datos, realizando una llamada al mtodo Delete de la tabla. Como ejemplo, presentamos el mtodo Delete del origen de datos del formulario LedgerJournalTable. Ejemplo de mtodo Delete void delete() { this.returnJournalNum(); super(); }

Pgina 74 de 141

Programacin de formularios

Es muy importante destacar que en un formulario los orgenes de datos enlazados son tratados como un nico origen de datos. Es decir, las operaciones de seleccin, actualizacin y creacin de registros desde el formulario se realizan sobre todas las tablas enlazadas. El mtodo Init se ejecuta tambin en todos los orgenes de datos. Por otro lado, los mtodos de notificacin (como el mtodo Active) se ejecutan tambin en todos los orgenes de datos.

4.2.

Acceso y modificacin de las consultas en los formularios


Todos los formularios con un origen de datos tienen una consulta activa, generada automticamente en el mtodo Init de dicho origen de datos. Como hemos visto anteriormente, existe una variable de sistema que nos da acceso a dicha consulta. En algunos casos es necesario modificar la consulta mediante programacin. Vamos a ver mediante un ejemplo, cmo modificar en tiempo de ejecucin los criterios de seleccin de la consulta de un formulario. El ejemplo corresponde al formulario CustTrans. En primer lugar, se declaran en el mtodo ClassDeclaration del formulario las variables que consideremos necesarias. Los tipos de datos de estas variables correspondern a clases de sistema. As, por ejemplo, la clase QueryBuildDataSource nos da acceso al origen de datos de una consulta y la clase QueryBuildRange nos da acceso al rango de seleccin de registros. La informacin acerca de los mtodos de estas clases puede encontrarse en la documentacin del sistema, dentro del Arbol de Objetos de la Aplicacin. Ejemplo class FormRun extends ObjectRun { QueryBuildDateSource QueryBuildRange } dataSource; criteriaOpen;

El nombre de las variables que corresponden a rangos de seleccin suele empezar con la palabra criteria. A continuacin deben inicializarse las variables de referencia. Para ello debe aadirse cdigo al mtodo del origen de datos. Las sentencias correspondientes deben insertarse despus de la llamada al mtodo super(), ya que ste es el encargado de crear la consulta. Hacer esto es equivalente a inicializar dichas variables antes de la llamada al mtodo super() en el mtodo Run. Ejemplo void init() { super(); dataSource = CustTrans_Q.dataSourceNo(1); criteriaOpen = dataSource.addRange(fieldnum(CustTrans,open)); }

Pgina 75 de 141

Programacin de formularios

Una vez inicializadas las variables, podremos modificar el rango de seleccin de registros. Esto se realiza antes de la llamada al mtodo super() del mtodo ExecuteQuery. Ejemplo void executeQuery() { criteriaOpen.value('0..1'); super(); } Como ya mencionamos anteriormente, en versiones ms antiguas de Axapta, no existan las variables declaradas implcitamente para las consultas. En ese caso habra que acceder a la consulta mediante mtodos de las clases de sistema, tal y como muestra el ejemplo: Ejemplo void init() { super(); dataSource = this.query().dataSourceNo(1); criteriaOpen = dataSource.addRange(fieldnum(CustTrans,open)); } Como podemos apreciar, sustituiramos la variable CustTrans_Q por this.query(), donde this hara referencia al origen de datos del formulario y query() sera el mtodo que nos devuelve la consulta de dicho origen de datos.

5.

Mtodos en los controles


En MorphX, adems de introducir cdigo en el propio formulario y en el origen de datos, podemos introducir cdigo en los controles de dicho formulario. Trataremos de codificar lo menos posible en los controles, dado que el cdigo que introduzcamos en estos mtodos no podr ser utilizado para otros elementos. Todos aquellos procesos generales que queramos realizar con el formulario deberemos codificarlos en los mtodos del propio formulario o en los del origen de datos. nicamente codificaremos en los controles, cuando queramos controlar su funcionalidad. La lista de mtodos de los controles es interminable, dado que existen muchos tipos de controles y cada uno de ellos tiene sus propios mtodos. Podemos obtener una lista completa de los mtodos en la Gua del desarrollador de Axapta. nicamente vamos a destacar por su importancia dos mtodos: a) Mtodo Clicked

Este mtodo existe en los controles de tipo CheckBox, Button, CommandButton y MenuItemButton. Se ejecuta cuando el usuario pincha sobre el control correspondiente.

Pgina 76 de 141

Programacin de formularios

En los botones de tipo MenuItemButton, la llamada al mtodo super() ejecuta el men item correspondiente. En el caso de los botones CommandButton, se ejecuta el comando asociado al botn. En los botones de tipo Button, la llamada a super() no realiza ninguna accin. b) Mtodo Lookup

Este mtodo existe en los controles de tipo StringEdit, IntEdit, RealEdit y DateEdit. Se ejecuta cuando el usuario pulsa el botn de lookup. Normalmente se aade cdigo a este mtodo cuando el desarrollador desea que se abra una ventana de bsqueda distinta de la ventana estndar.

6.

Secuencia de ejecucin de mtodos


Cuando realizamos acciones sobre un formulario, ejecutamos los mtodos del propio formulario y los de su origen de datos. La ejecucin de estos mtodos sigue una secuencia determinada, que nos va a condicionar el funcionamiento del sistema. Por lo tanto, es muy importante conocer esa secuencia, ya que esto nos permitir poder determinar qu mtodo debemos codificar para obtener los resultados esperados. Por ejemplo, veamos en el siguiente esquema qu mtodos se ejecutan cuando abrimos un formulario:

Figura 9. Apertura de un formulario. Secuencia de ejecucin de mtodos.

La secuencia de ejecucin de mtodos es la siguiente: 1. 2. 3. 4. 5. 6. Mtodo constructor New. Mtodo Init del formulario. Mtodo Init del origen de datos del formulario. Mtodo Run del formulario. Mtodo ExecuteQuery del origen de datos del formulario. Mtodo NextField del formulario.

A continuacin, vamos a ver la secuencia de ejecucin que tiene lugar cuando cerramos un formulario. Podemos apreciarla en el siguiente esquema:

Pgina 77 de 141

Programacin de formularios

Figura 10. Cierre de un formulario. Secuencia de ejecucin de mtodos.

La secuencia de ejecucin de mtodos es la siguiente: 1. Mtodo CloseCancel del formulario. 2. Mtodo CanClose del formulario. 3. Mtodo Close del formulario. Por ltimo, vamos a ver qu mtodos se ejecutan cuando salimos de un control de un formulario:

Figura 11. El usuario sale de un control. Secuencia de ejecucin de mtodos.

La secuencia de ejecucin de mtodos es la siguiente: 1. 2. 3. 4. 5. 6. Mtodo Leave del control. Mtodo Validate del control. Mtodo Modified del control. Mtodo Validate del origen de datos del formulario. Mtodo ValidateField de la tabla. Mtodo Modified del origen de datos del formulario.

Pgina 78 de 141

Paso de parmetros entre objetos: La clase Args

Paso de parmetros entre objetos: La clase Args


1. Comunicacin entre objetos
Es posible establecer comunicacin entre dos objetos de la aplicacin cuando uno de ellos se genera a partir de otro. Esto podemos realizarlo de diferentes maneras: 1. Desde un men item creamos otro elemento de la aplicacin (formularios, informes, clases). El objeto que se crea puede tomar una serie de parmetros del men item. 2. Desde un formulario podemos abrir otro formulario o bien un lanzar la ejecucin de un informe. El formulario y el nuevo objeto estarn relacionados y existir entre ellos una va de comunicacin a travs de la cual podremos pasar al nuevo objeto informacin acerca del formulario y del registro activo. 3. Podemos crear un nuevo objeto desde cdigo y pasarle una serie de parmetros. 4. Podemos crear un men item desde cdigo y lanzar con l un objeto.

2.

La clase Args
La clase Args es una clase de sistema que nos permite pasar argumentos a los objetos de la aplicacin. Podemos encontrar ayuda acerca de esta clase en el nodo Documentacin del sistema del rbol de Objetos de la Aplicacin. A continuacin, se presenta la lista de mtodos de la clase Args. Para cada mtodo se describe su utilizacin en el objeto invocante y en el invocado.

Nombre del mtodo Void new object p2) Int finalize() Object caller (Object p1) (AnyType

En el objeto invocante p1, El constructor.

En el objeto invocado

El destructor Almacena informacin sobre Utiliza el valor de retorno qu objeto ha creado el para determinar desde nuevo objeto. donde fue llamado el objeto actual. Obtiene el nombre del origen de datos del formulario que ha hecho la llamada.

TableId dataset()

Pgina 79 de 141

Paso de parmetros entre objetos: La clase Args

Str name (str 250 p1)

Slo es usado por la clase ClassFactory. Almacena una referencia a Usado por la un objeto. ClassFactory para objetos nuevos. clase crear

Object object (object p1)

Str parm (Str 250 p1)

Almacena un parmetro (una Se usa para recuperar un cadena). parmetro del objeto invocante. Almacena un valor Se usa para recuperar un enumerado del tipo valor enumerado del objeto especificado en el mtodo invocante. ParmEnumType. Define el tipo de enumerado Se usa para determinar el que va a ser pasado en el tipo de enumerado usado mtodo ParmEnum. por el objeto invocante.

AnyType parmEnum (int Enum)

Int parmEnumtype( int EnumType)

Object parmObject (Object Almacena un objeto que va a Se usa para recuperar un p1) ser pasado como parmetro. objeto del objeto invocante. Common record (common Almacena un registro. p1) Se usa este mtodo para recuperar el registro activo del objeto invocante.

Todos los formularios, informes y consultas utilizan la clase Args como su primer argumento en el constructor. El modo preferido para usar la clase Args es construir un objeto de tipo Args, asignarle un nombre y entonces pasarle el objeto Args al formulario o a un mtodo de la clase ClassFactory. Veamos, a continuacin, un ejemplo de utilizacin de la clase Args para pasar parmetros a un formulario creado desde el cdigo. Ejemplo: void method1() { Args args; fr;

FormRun ;

args = new Args(CustTable); fr = ClassFactory.formRunClass(args); fr.init(); fr.run(); } Algunos mtodos de la clase Args corresponden con propiedades de los men items. En la tabla siguiente se define esta correspondencia:

Pgina 80 de 141

Paso de parmetros entre objetos: La clase Args

Mtodo clase Args parm parmEnum parmEnumType parmObject

Propiedad men item Parameters EnumParameter EnumTypeParameter Object

Supongamos que abrimos un formulario desde un men item. Veamos cmo recuperar los parmetros de entrada. Para ello, presentamos el mtodo ExecuteQuery del origen de datos de un formulario. En este mtodo, se modifica el rango de seleccin de registros de la consulta en funcin de los parmetros especificados en el men item. Ejemplo: void ExecuteQuery() { switch (element.Args().ParmEnum()) { case (PastFuture::Past): criteriaPastFuture.value(..+date2StrDMY(today())); break;

case (PastFuture::Future): criteriaPastFuture.value(date2StrDMY(today())+..); break; default: } }

Pgina 81 de 141

Programacin de informes

Programacin de informes
1. Introduccin
Los informes se utilizan para obtener copias impresas de la informacin almacenada en la base de datos del sistema. Como en otros elementos de Axapta, podemos introducir cdigo en los informes para ampliar su funcionalidad. Existen distintos mbitos en los informes donde podemos aadir cdigo: Informe propiamente dicho Consulta del origen de datos del informe Secciones del informe Dependiendo de la funcionalidad que queramos implementar en el informe, escribiremos el cdigo en un mbito o en otro. No obstante, normalmente, se siguen las siguientes reglas: Codificamos en los mtodos del propio informe, cuando queremos controlar la funcionalidad general del mismo. Codificamos en los mtodos de la consulta del origen de datos, cuando queremos controlar la funcionalidad de los datos que aparecen en el informe. Codificamos en las secciones del informe, cuando queremos controlar la funcionalidad de alguna de las secciones o el comportamiento de alguno de los elementos especficos que aparecen en el informe.

Como ya se vio en el captulo de programacin de formularios, se debe tener en cuenta que el cdigo que se introduce en un informe ser accesible nicamente desde dicho informe.

2.

Variables del sistema


Tal y como ocurra con los formularios, cuando trabajamos con los informes, algunas variables son declaradas implcitamente por el sistema. Adems de estas variables, es conveniente recordar que en cualquier momento, la variable this nos da acceso al elemento al que pertenece el mtodo que estamos modificando. A continuacin se describen las variables de sistema de los informes y los elementos a los que dan acceso: a) Informe

Pgina 82 de 141

Programacin de informes

Una variable llamada element de tipo ReportRun referencia al objeto informe al completo. b) Tabla

Por cada uno de los orgenes de datos del informe tendremos una variable con el nombre del origen de datos, que nos referencia la tabla asociada a dicho origen de datos. En realidad, en un momento dado esta variable nos da acceso al registro activo. Suponiendo que tuviramos un origen de datos que se llamara DatosInforme, tendramos una variable con ese nombre que hara referencia a la tabla. Esta variable nos permite hacer dos cosas: 1. Llamar a un mtodo definido en la tabla. Por ejemplo: DatosInforme.insert(); 2. Hacer referencia a los campos individuales de la tabla. Por ejemplo: number = DatosInforme.accountNo; c) Consulta Existen dos variables que nos dan acceso a la consulta de un informe: Una variable llamada QUERY de tipo Query, que hace referencia a las propiedades y los mtodos de la consulta del informe. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: query.levelNo(1); Una variable llamada QUERYRUN de tipo QueryRun, que hace referencia a las propiedades y mtodos de una instancia en ejecucin de la consulta del informe. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: queryRun.getNo(1); A pesar de que se existen estas variables, declaradas automticamente por el sistema, podemos acceder a los elementos que referencian de la forma tradicional, es decir, desde cdigo haciendo uso de los mtodos de la clase de sistema ReportRun. As, por ejemplo, desde un mtodo del informe podemos acceder a la consulta del siguiente modo: Ejemplo de acceso a una consulta Query ; q = this.query(); q.levelNo(1); Ejemplo de acceso a la instancia en ejecucin de una consulta QueryRun ; qr; q;

Pgina 83 de 141

Programacin de informes

qr = this.queryRun(); qr.getNo(1); En ambos casos la variable this hara referencia al objeto en ejecucin en ese momento, es decir, al informe.

En cualquier caso, siempre es ms aconsejable utilizar las variables implcitas declaradas por el sistema en lugar de definir nuevas variables, ya que de esta forma evitamos que existan variables iguales duplicadas en memoria.

3.

Mtodos del informe


Cuando creamos un nuevo informe se crea automticamente un nodo de mtodos. El nodo contiene lo que se denomina mtodos virtuales, que son mtodos implementados en MorphX, pero que pueden ser sobrecargados para cambiar el comportamiento por defecto de los formularios. En estos mtodos la funcin llamada super() activa la ejecucin del mtodo implementado por MorphX.

3.1.

Lista de mtodos
En un informe podemos encontrar los siguientes mtodos de sistema:

Finalize

Se ejecuta cuando ya no se necesita la instancia del informe en ejecucin.

Prompt

Se ejecuta para solicitar al usuario que elija el medio (papel, pantalla, archivo) y otra informacin de impresin.

Init

Se ejecuta cuando se crea un informe.

Run

Se ejecuta para poner en funcionamiento el informe.

Fetch

Se ejecuta para recuperar registros de la base de datos.

Print

Se ejecuta para imprimir el informe en el medio de impresin seleccionado.

Send

Se ejecuta para enviar los registros recuperados por la consulta a las distintas secciones del informe.

SetTarget

Se ejecuta por el formulario SysPrintForm cambiamos de medio de impresin.

cuando

Pgina 84 de 141

Programacin de informes

GetTarget

Se ejecuta por el formulario SysPrintForm cambiamos de medio de impresin.

cuando

PrinterSettings

Se ejecuta cuando seleccionamos la opciones de impresin en un men o a travs del formulario SysPrintForm.

Caption

Se ejecuta cuando se pone en marcha el informe y determina el ttulo de la ventana de visualizacin preliminar del informe.

CreateProgressForm

Se ejecuta cuando se crea una ventana que indica el progreso en la construccin del informe.

ProgressInfo

Se ejecuta cada vez que se va a actualizar la ventana de progreso.

3.2.

Mtodos principales y su funcin


A continuacin vamos a describir algunos de los mtodos ms utilizados en los informes, que por su importancia merecen un tratamiento algo ms exhaustivo. a) Mtodo ClassDeclaration En ste mtodo se definen las variables globales del informe que son accesibles desde cualquier mtodo del informe o de cualquier seccin del mismo. Los mtodos de la consulta no tienen acceso a estas variables globales. b) Mtodo Init El mtodo Init se ejecuta cuando abrimos un informe. La llamada al mtodo super() crea una instancia en ejecucin del informe. Es automticamente activado despus de un mtodo new. En el mtodo Init, se inicializan las variables especficas de dicho informe. Como ejemplo, tenemos el mtodo Init del informe CustRevenue. Ejemplo de mtodo Init public void init() { super(); custRevenueReport = element.args().caller(); if (!custRevenueReport) throw error(strfmt("@SYS22338",funcname()));

Pgina 85 de 141

Programacin de informes

} c) Mtodo Prompt El mtodo Prompt se ejecuta para solicitar al usuario que elija el medio de impresin. Se muestra un dilogo en pantalla, donde podemos elegir entre las distintas opciones de impresin. Si el programador no quiere que aparezca este dilogo, el mtodo Prompt puede sobrecargarse, de manera que no realice la llamada a super(). No hay que confundir este mtodo con el mtodo del mismo nombre de una consulta. Como ejemplo, tenemos el mtodo Prompt del informe Cheque. Ejemplo de mtodo Prompt boolean prompt() { boolean ret; ; if (chequeCopy) ret = true; else ret = super(); return ret; } d) Mtodo Run El mtodo Run se ejecuta cuando abrimos un informe, inmediatamente despus del mtodo Init, para poner en funcionamiento el informe. La versin no sobrecargada de este mtodo realiza cinco tareas en la siguiente secuencia: 1. 2. 3. 4. 5. Llamar al mtodo Prompt Crear un diseo bsico para el informe, si an no existe Organizar los campos en el informe Llamar al mtodo Fetch Llamar al mtodo Print

Antes de la llamada al mtodo super() podramos hacer algunas tareas habituales, como por ejemplo modificar la consulta del informe. Como ejemplo, tenemos el mtodo Run del informe ForecastSalesActual. Ejemplo de mtodo Run public void run() { ReportStringControl ReportStringControl ctrlBudget; ctrlActual;

Pgina 86 de 141

Programacin de informes

; ctrlBudget = element.design().controlName('BudgetInterval'); ctrlBudget.leftValue(ctrlBudgetQty.leftValue()); ctrlActual = element.design().controlName('ActualInterval'); ctrlActual.leftValue(ctrlActualQty.leftValue()); super(); }

3.3.

Secuencia de ejecucin de mtodos


En la siguiente figura se muestra la secuencia de ejecucin de mtodos cuando abrimos un informe:

Figura 12. Secuencia de ejecucin de mtodos en un informe.

El orden en el que se ejecutan los mtodos es el siguiente: 1. Se activa el mtodo Init del informe, para inicializarlo. 2. Se activa el mtodo Run del informe. 3. Se activa el mtodo Prompt del informe, para permitir al usuario interactuar con l. 4. Se activa el mtodo Fetch del informe. 5. Se activa el mtodo Print del informe.

3.4.

Seleccin del diseo de un informe


Los informes en MorphX pueden tener ms de un diseo. Podemos utilizar esto para tener distintas versiones del mismo informe. Por ejemplo, podemos tener un informe con dos diseos, donde el primero imprimira con orientacin vertical y el segundo con orientacin horizontal o apaisada.

Pgina 87 de 141

Programacin de informes

Cuando imprimimos un informe, el primer diseo es el utilizado por defecto. Sin embargo, en tiempo de ejecucin podemos abrir un diseo especfico en funcin de alguna condicin. Para ello utilizaremos el mtodo design() de la clase ReporRun. Como ejemplo, veamos parte del mtodo Init del informe SalesInvoice, correspondiente a las facturas de venta: Ejemplo void { super(); ... switch(SalesParameters::find().prePrintLevelInvoice) { case(PrePrintLevel::BlankPaper): element.design('BlankPaper'); break; case(PrePrintLevel::SemiPrePrinted): element.design('SemiPrePrinted'); break; case(PrePrintLevel::PrePrinted): element.design('PrePrinted'); break; } ... } init()

3.5.

Mtodos Fetch y Send


La consulta, utilizada para recuperar registros de la base de datos, y el diseo de un informe son dos elementos independientes. Estos dos elementos, slo interaccionan de manera dinmica mediante los mtodos que vamos a definir en este apartado. La consulta puede hacer referencia al informe utilizando la variable predefinida element. Si lo necesitamos, el informe puede acceder a la consulta, utilizando la variable query. Los mtodos Fetch y Send son una parte central del motor de los informes en MorphX. El mtodo Fetch recoge los registros definidos por la consulta del informe, y el mtodo Send enva los registros recogidos al diseo del informe. El mtodo Fetch es el principal bucle de un informe. Si los datos que se van a mostrar en el informe deben cumplir restricciones especiales, el programador puede sobrecargar el mtodo Fetch. La estructura bsica del mtodo Fetch es la siguiente:

Pgina 88 de 141

Programacin de informes

QueryRun qr = new QueryRun(report); // Abrir el dilogo prompt if (qr.prompt()) { while (qr.next()) { file = qr.get(file); send(file): } } Si slo queremos imprimir registros que satisfacen condiciones especiales, que sean difciles de expresar como un rango en la consulta, debemos escribir el cdigo situado arriba, y solo permitir la llamada al mtodo Send si la restriccin (expresada como una funcin con el mismo nombre en el ejemplo de abajo) se satisface. while (qr.next()) { file = qr.get(file); if (restriccin()) send(file); } A continuacin presentamos un ejemplo del mtodo Fetch del informe Cheque. Ejemplo de mtodo fetch boolean fetch() { QueryRun ; query = new QueryRun(this); if (query.prompt() && element.prompt()) { query.setRecord(tmpCheque); while (query.next()) { tmpChequePrintout = query.getNo(1); this.send(tmpChequePrintout); } return true; query; // Para todos los orgenes de datos // Para todos los orgenes de datos // el usuario no ha pulsado el botn de cancelar

Pgina 89 de 141

Programacin de informes

} return false; } El mtodo Send es una conexin entre la consulta y la parte visual del informe. El mtodo Send enva los registros recogidos a las secciones del cuerpo (body sections) del informe. Podemos ver un esquema del flujo de informacin en los informes en el dibujo siguiente:

Figura 13. Flujo de informacin en un informe.

En la figura podemos ver cmo los datos se envan desde la tabla a la consulta del formulario mediante el mtodo Fetch, y despus como se enlazan esos datos con los controles del diseo del informe mediante el mtodo Send.

4.

Mtodos en la consulta
En la Gua del desarrollador de Axapta podemos encontrar la lista completa de mtodos de las consultas. En este apartado vamos a ver nicamente los ms importantes. a) Mtodo ClassDeclaration En ste mtodo se definen las variables globales de la consulta, que sern accesibles nicamente por sus mtodos. b) Mtodo Init El mtodo Init incializa la consulta del informe cuando sta se ejecuta. c) Mtodo Prompt

Pgina 90 de 141

Programacin de informes

La ejecucin de este mtodo presenta un dilogo en pantalla, donde el usuario podr determinar los rangos de seleccin de registros, el orden en que stos deben presentarse, etc. La llamada al mtodo super(), abre el formulario definido en la propiedad Form de la consulta. Por defecto, esta propiedad toma el valor SysQueryForm. Si el programador no quiere que aparezca este dilogo, el mtodo Prompt puede sobrecargarse, de manera que no realice la llamada a super(). Como ejemplo, tenemos el mtodo Prompt del informe Cheque. Ejemplo de mtodo Prompt boolean prompt() { boolean ret; ; ret = true; return ret; } d) Mtodo Run El mtodo Run se ejecuta cuando ejecutamos la consulta de un informe desde el Arbol de Objetos de la Aplicacin. //No muestra la ventana

5.

Mtodos en secciones de un informe


Las secciones determinan la apariencia de un informe en MorphX. Estas secciones, pueden ser definidas por una plantilla o directamente en el diseo particular de un informe. Todas las secciones pueden ser repetidas un nmero determinado de veces, segn las necesidades del usuario. En la tabla siguiente se presentan las diferentes secciones que pueden componer un informe:

Prlogo (Prolog)

Aparece al principio de un informe. Se utiliza para mostrar elementos, como por ejemplo el logotipo, el ttulo del informe, o la fecha actual. El prlogo se imprime antes que el encabezado de pgina, en la primera pgina del informe.

Encabezado de pgina (Page Header) Encabezado (Header)

Aparece al principio de cualquier pgina de un informe.

Aparece al principio de un nuevo grupo de registros. Se utiliza para mostrar elementos, como por ejemplo el nombre de un grupo.

Pgina 91 de 141

Programacin de informes

Seccin (Section Group)

Aparece en la parte central de un informe. Una seccin puede contener un encabezado, un cuerpo y un pie. Es importante sealar, que la estructura de los orgenes de datos se ve reflejada en la estructura de las secciones.

Cuerpo (Body)

Aparece en la parte central de un informe. Un cuerpo contiene controles o una seccin. Los controles muestran la informacin de los campos de los orgenes de datos.

Pie (Footer)

Aparece al final de un grupo de registros. Se utiliza para mostrar, por ejemplo, subtotales.

Pie de pgina (Page Footer)

Aparece al final de cada pgina de un informe. Se utiliza para mostrar, por ejemplo, nmeros de pgina.

Eplogo (Epilog)

Aparece al final de un informe. El eplogo se imprime justo despus del pie de pgina de la ltima pgina del informe.

Seccin programable (Programmable Section)

Podemos utilizar secciones programables para aadir cualquier tipo de informacin personalizada a nuestros informes. Para activar una seccin programable, lo hacemos mediante la llamada explcita al mtodo execute.

Por lo tanto, la estructura de un informe sera la siguiente: [Prolog] [Page Header] [Section Group] [Header] [Body] [Footer] [Section Group] [Header] [Body] [Footer] [Page Footer] [Epilog] En cualquier lugar del informe podemos definir Secciones programables. De la misma manera, en cualquier seccin del diseo de un informe, podemos crear mtodos de tipo display, que nos permitiran producir la informacin que quisiramos mostrar en dicho informe.

Pgina 92 de 141

Programacin de informes

En el diseo de un informe, debajo de cada seccin, existe un mtodo llamado ExecuteSection. Cuando ejecutamos el mtodo super(), dentro de un mtodo de este tipo, se imprime la informacin de dicho sector. En determinadas situaciones, nos interesa controlar si la informacin de una seccin queremos que se imprima o no, de acuerdo con algn criterio que nosotros mismos definimos. Esto se consigue haciendo que la llamada al mtodo super() se realice dentro de una instruccin condicional. Tambin podemos utilizar el mtodo ExecuteSection para esconder o mostrar controles de un informe en tiempo de ejecucin. Otra utilidad comn de los mtodos ExecuteSection es insertar un salto de pgina. Por ejemplo, para insertar un salto de pgina entre el prlogo y las pginas siguientes, debemos insertar la instruccin element.newPage() despus de la llamada al mtodo super() en el mtodo ExecuteSection del prlogo.

6.

Acceso a los controles desde el cdigo


En algunas ocasiones puede interesarnos modificar alguna propiedad de un control en tiempo de ejecucin. Para poder acceder a los controles de un informe, lo primero que tenemos que hacer es declarar una variable del tipo correspondiente en el mtodo ClassDeclaration: Ejemplo declaracin de controles public class ReportRun extends ObjectRun { ReportSection ReportTextControl } A continuacin debemos asignar a esa variable de tipo control el control del informe. Supondremos que tenemos una seccin llamada Prolog_1 y dentro de ella un control de tipo texto llamado PrologText1. Realizaramos la asignacin con una instruccin como la siguiente: Ejemplo de asignacin de control a una variable public void init() { reportSection = element.design().sectionName("Prolog_1"); textControl = reportSection.controlName("PrologText1"); } Hay que destacar que en los controles de los informes no tenemos la propiedad de declaracin automtica (Autodeclaration), lo que har, que tengamos de declarar variables para todos los controles del informe a los que queramos acceder en tiempo de ejecucin. reportSection; textControl;

Pgina 93 de 141

Plantillas de informes

Plantillas de informes
1. Definicin
La idea bsica de una plantilla es muy simple. Imaginemos que tenemos 20 informes para una determinada compaa, que comparten el mismo diseo bsico. Si definimos el diseo bsico en una plantilla slo lo realizaremos una vez, y despus el mismo diseo podr ser compartido por todos los informes de dicha compaa. Cuando creamos un informe utilizando una plantilla, estamos determinando unas caractersticas por defecto. La plantilla contiene informacin sobre las secciones que contiene un nuevo informe y sobre el diseo de cada una de las partes del informe. Una plantilla puede contener un prlogo, una cabecera de pgina, un pie de pgina, un eplogo, y secciones programables. Estas secciones pueden ser aadidas al diseo que MorphX genera basndose en nuestro diseo especfico. Por ejemplo, nuestra plantilla contiene un pie de pgina que aade un nmero de pgina a todas las pginas de nuestro informe. Si nosotros decidimos hacer una modificacin en el diseo, tan slo lo tendremos que hacer una vez en la plantilla, y automticamente todos los 20 informes sern modificados. Esto es cierto nicamente cuando utilizamos un informe basado en un diseo especifico (AutoDesignSpecs). Si nuestro informe utiliza un diseo personalizado (Design), los cambios realizados en la plantilla no los veremos en nuestro informe. Cuando nosotros creamos un diseo personalizado, MorphX realiza una copia de la plantilla y la coloca en el nodo diseo de nuestro informe, por esta razn no se actualiza cuando se modifica la plantilla.

2.

Construccin de una plantilla


Una plantilla consiste en un nmero de secciones. Cada seccin define una parte del informe, como por ejemplo, un prlogo, una cabecera de pgina, un pie de pgina, un eplogo o una seccin programable. Cada uno de estos componentes del diseo puede contener un nmero de controles para visualizar diversos tipos de informacin. Para crear una nueva plantilla debemos acceder al nodo Report Templates que se encuentra bajo el nodo Reports del AOT. En este nodo, simplemente deberemos elegir la opcin Nuevo del men contextual. A continuacin, renombramos la plantilla y generamos las secciones que deseemos.

3.

Utilizacin de una plantilla en un informe


Para utilizar una plantilla en un informe, simplemente debemos introducir el nombre de la plantilla elegida en la propiedad ReportTemplate del nodo ReportDesign del informe.

Pgina 94 de 141

Clases

Clases
DEFINICIN: Una clase es un constructor software que define unos datos (estado) y unas acciones (comportamiento) de los objetos concretos que posteriormente son creados en a partir de esa clase. Las propiedades son los datos para la clase y los mtodos son la secuencia de sentencias que operan con los datos. Normalmente las propiedades son propias de un objeto, es decir, todos los objetos construidos a partir de la definicin de la clase tendrn su propia copia de las propiedades. Estos distintos objetos son conocidas como instancias. Una clase no es un objeto. Una clase puede ser considerada como un anteproyecto, que define como un objeto podr comportarse cuando el objeto sea creado desde las especificaciones dictadas por la clase. Nosotros obtenemos objetos concretos para instanciar una clase definida previamente. As como nosotros podemos construir muchas casas de un mismo arquitecto, nosotros podemos instanciar muchos objetos de una misma clase. A continuacin podemos ver una declaracin bsica de una clase muy simple llamada Point: Class Point { double x; double y; } Esta declaracin simplemente define una plantilla de cmo objetos de tipo Point pueden ser instanciados. //instancia de una propiedad // instancia de una propiedad

1.

Objetos
Casi todo puede ser considerado como objeto. Coge, por ejemplo, una botella de agua mineral. Tiene un estado y varios mtodos. Puedes usar el mtodo vaciar agua para cambiar el estado del objeto. Hay menos agua en la botella cuando finaliza la accin. Activas los mtodos y el estado del objeto cambia de acuerdo a ello. El estado recuerda el efecto de la operacin que has activado. Otro ejemplo es el de un coche a control remoto. El coche consiste en funcionalidad y datos. Los datos estn influidos por los mtodos o la funcionalidad. Velocidad, direccin, rotacin, y, as sucesivamente, son datos o variables. Accedes a los mtodos del coche cuando usas el control remoto. Por ejemplo mandas un mensaje de moverse hacia delante, el cual sabes que es un mtodo (funcionalidad) que pertenece al objeto coche. El mensaje es interpretado por el coche que activa el mtodo de moverse hacia delante, el cual resulta en un movimiento de las ruedas y un movimiento hacia delante. El control remoto es el manipulador que utilizas para acceder al objeto, o apuntar al objeto. El cdigo es as: ClassName Myhandle=new ClassName();

Pgina 95 de 141

Clases

ClassName

Myhandle

ClassName

Un Ejemplo de datos en el coche podra ser tambin la energa de las bateras. No sabes cuanta energa puede quedarle a la batera, antes preguntas al objeto, en otras palabras, debes comprobar la batera. Slo el objeto conoce esos datos. Tienes que conocer los objetos mtodos del objeto, antes de poder activarlos y poder tener algn manejo para poder acceder a ellos. El coche podra tener un mtodo llamado fuel, el cual utilizas para cambiar el estado de la batera. No puedes acceder a los mtodos del coche sin el control remoto. Los objetos interactan con otros en la aplicacin. Uno objeto interacta con otros objetos envindole un mensaje, el cual invoca una operacin en el objeto que la recibe. El objeto recibiente sabe como reaccionar a este mensaje, y diferentes objetos pueden fcilmente reaccionar de forma distinta ante el mismo mensaje.

2.
2.1.

Mtodos de la clase
ClassDeclaration.
En este mtodo es donde podemos escribir la declaracin de las variables. Por defecto este mtodo est vaco. Tambin en este mtodo es donde se le asigna un nombre a la clase. Ejemplo: class CustOverdueExpense { CustPaymExpense LedgerAccount LedgerJournalTrans } custPaymExpense; ledgerAccount; ledgerJournalTrans;

Pgina 96 de 141

Clases

2.2.

New.
Este constructor es llamado automticamente cuando el objeto es creado por el operador new. Suele ser utilizado para inicializar las propiedades en el objeto nuevo. A continuacin vemos un ejemplo de la utilizacin del mtodo new en la clase Point: Void new(double a=10, double b=10) {//Constructor que inicializa a un valor por defecto x = a; y = b; } Al mtodo new en una clase se llama constructor. Cuando nosotros creamos una instancia de un objeto de la clase Point, el constructor es invocado para ejecutar cualquier inicializacin que sea necesaria. En este caso, modifica la instancia de la variable a un estado inicial. Los mtodos constructores pueden o no recibir parmetros, pero nunca devuelven un valor. En el ejemplo de abajo podemos ver como podemos crear e inicializar un objeto de la clase Point, inicializndolo con los valores por defecto o inicializndolo a unos valores especficos. Point lowerleft; Point upperRight;

lowerleft = new Point(); //valores por defecto. upperRight = new Point(100.0, 200.0); // valores especficos.

2.2.1.

Creacin de otros objetos desde un constructor

En ocasiones una clase necesita utilizar instancias de otros objetos, y debe en su constructor crearse instancias de dichos objetos. A continuacin podemos ver un ejemplo de cmo la clase rectangle utiliza dos objetos de tipo Point. Class Rectangle { Point lowerleft; Point upperRight;

New() { lowerleft = new Point(); upperRight = new Point(); } }

2.3.

Finalize.

Pgina 97 de 141

Clases

Cuando el manejo de un objeto no puede agregarse a un objeto, el objeto ya no podr extenderse. Si quieres terminar un objeto, usa el mtodo llamado FINALIZE. El mtodo libera el espacio que estaba ocupado por el objeto. Un manipulador siempre apuntar a algo, pero puede usarse el valor Null para interrumpir el enlace del manipulador del objeto con el objeto. Esto no har desaparecer el objeto. El ejemplo siguiente describe la diferencia entre dos acciones: Class1 oh; oh = new Class1(); objecthandle Su = Null; Or: Su.finalize(); // The object is terminated, and any code in Finalize is executed //Objecthandle of the oh type is created //Object of the type Class1 is created and attached //to the

// The link to the object is terminated

Se puede usar el mtodo Finalze para optimizar las acciones teardown. ste fragmento de cdigo ilustra como activar el mtodo finalize en una clase. Observa que Finalize en X++ no es llamado automticamente por el sistema. Se debe explictar la llamada al mtodo finalize para ejecutar los estados que hay en l. // From any method in a class { ... if (Condition) this.Finalize(); ... } Aunque el mtodo finalize no contiene ningn cdigo, la ejecucin del mtodo tiene un efecto importante. Cuando llamas a Finalize, MorphX cierra el objeto. Esto significa que usando finalize un objeto se puede quitar a s mismo de la memoria.

3.

Mtodo main
Este mtodo es utilizado para ejecutar una clase. No es un mtodo de la clase, si no que cuando nosotros queremos ejecutar una clase a travs de una llamada de menu item, nos crearemos un mtodo main pasndole como parmetro un objeto de tipo Args. Este mtodo tiene 3 peculiaridades: 1.- Es un mtodo esttico.

Pgina 98 de 141

Clases

2.- Recibe un nico parmetro de tipo args. 3.- No devuelve ningn parmetro, es de tipo void. El perfil de este mtodo es el siguiente. void static main (args _args); Una clase puede ser ejecutada a travs de un men item de tipo Action o sobre la misma clase pulsando Open (botn derecho del ratn o en la barra de herramientas). Normalmente este mtodo suele contener la creacin de la instancia de la clase y las llamadas a los mtodos prompt y run de la clase. Ejemplo: static void { CustInvoiceJour CustInvoice ; custInvoiceJour = args.record(); custInvoice = new CustInvoice(custInvoiceJour, CustParameters::find().creditMaxCheck); custInvoice.run(); } custInvoiceJour; custInvoice; main(Args args)

4.

Declarando variables de los objetos


La sintaxis de la declaracin de variables para clases es la siguiente:

Declaracin Objeto Variable Initialization

= ClaseDefinidaPorUsuario Variable{,Variable } ; = Identificador | Identificador Inicializacin = new NombreClase ( Parmetro { , parmetro } )

Donde ClaseDefinidaPorUsuario es el nombre del objeto de la aplicacin en el rbol de la Aplicacin de Axapta. Usando esto se pueden declarar variables como stas. Access A1; //Un objeto-acceso es declarado pero NO inicializado Access A2,A3; //Dos objetos accesos son declarados, pero no inicializados. Access A4 = new Access(); //Un objeto acceso es declarado E inicializado //(sin parmetros)

Pgina 99 de 141

Clases

Una variable es una referencia, o puntero, a una parte de la memoria que contiene el objeto almacenado. Pero desde la variable solo es una referencia (Object andel), debes asignar espacio para el objeto antes de que puedas usarlo para contener datos. En los ejemplo de arriva, el objeto A4 es declarado usando el nuevo mtodoen la Access-class(new access()) como una inicializacin, la memoria es tambin asignada. Los otros objetos-accesos(A1,A2 y A3) son slo declarados y por lo tanto slo (nulos) punteros. Como los objetos A1-A3 son declarados, pueden apuntar a cualquier objeto asignado, o ellos mismos pueden saignarse invocando el mtodo new en ellos. En la siguiente ejemplo, la memoria es asignada para A2 y A3 y A1 es asignada para referenciar al objeto A4: A2 = new Access(); A3 = new Access(); A1 = A4;

5.

Herencia
X++ implementa lo que se conoce como un modelo de herencia simple. Una nueva clase slo puede ser subclase de otra clase. Si nosotros extendemos una clase, nosotros heredamos todos los mtodos y variables de la clase madre, la cual se llama superclase. La sintaxis que denota que una clase es hija de una superclase es la siguiente: Class Nombre de la clase hija extends nombre de la superclase La anterior sera la definicin que debera a parecer en la declaracin de clase de la clase hija. A continuacin presentamos un ejemplo que crea una nueva clase que es una variante de la clase Point, esta nueva clase vamos a llamarla 3DPoint: class Point { real x; // instancia de la variable. Real y; // instancia de la variable. ; New(real _x, real _y) { // el constructor inicializa las variables x e y. x = _x; y = _y; } } class 3DPoint extends Point { real z; // la coordinada z del punto.

Pgina 100 de 141

Clases

New(real _x, real _y, real _z) { super(_x, _y); // inicializa las instancias z = _z; } } Como podemos observar la clase 3DPoint ha aadido una nueva instancia de variable para la coordinada z del punto. Las instancias x e y son heredadas de la clase Point por lo que no necesitamos declararlas en la clase 3DPoint.

5.1.

Sobrecarga de mtodos
Cuando nosotros estamos trabajando con mtodos en una subclase, es decir, una clase que hereda mtodos y propiedades de otras clases, podemos alterar la funcionalidad del mtodo de la clase principal. Para hacer esto debemos crearnos en la subclase un mtodo con el mismo nombre y parmetros que el mtodo de la clase principal. Por ejemplo, supongamos que tenemos dos clases llamadas ClassA y ClassB, de forma que la segunda es una subclase de la primera. Definimos los siguientes mtodos: ClassA void myMethod(int i) { // Intrucciones clase A } ClassB void myMethod(int i) { // Instrucciones clase B } En este caso la clase ClassB es una subclase de la clase ClassA, por lo tanto hereda el mtodo myMethod. Sin embargo como en la clase ClassB se define un mtodo con el mismo nombre y el mismo nmero de argumentos, haramos caso omiso del mtodo de la clase principal. Si se llamara al mtodo myMethod de la clase ClassB ejecutara su propio mtodo, es decir, las instrucciones de la clase B, en lugar del mtodo de la clase principal. Esto es lo que llamamos sobrecargar un mtodo. Si no estamos interesados en perder por completo la funcionalidad del mtodo de la clase principal, pero nos interesa aadirle funcionalidad, podemos hacer una llamada al mtodo de la clase principal mediante la sentencia super()dentro del mtodo de la clase hija. Por ejemplo: ClassB void myMethod(int i) {

Pgina 101 de 141

Clases

super(); // Instrucciones clase B } En este caso cuando realizramos una llamada al mtodo myMethod de la clase hija se ejecutara, mediante la llamada super(), el mtodo de la clase principal, con lo que se ejecutaran las instrucciones de la clase A y despus se ejecutara el resto del mtodo, es decir, las instrucciones de la clase B. Por otra parte, con este funcionamiento existe el peligro de que, al sobrecargar un mtodo, alteremos su funcionalidad de manera incorrecta. Por lo tanto, para protegernos de este tipo de situaciones, X++ proporciona el modificador final, que evita que un mtodo pueda ser sobrecargado. Por ejemplo: final void myMethod() { // Instrucciones } Existen no obstante algunos mtodos que no pueden utilizar el modificador final, como son los que se invocan cuando se crea o destruye un objeto, y otros que no lo necesitan ya que nunca pueden ser sobrecargados, como son los mtodos estticos.

5.2.

Herencia controlada por constructor


Vamos va explicar con un ejemplo como trabaja la herencia controlada por constructor. En el siguiente ejemplo tenemos 5 clases: CLASE PT_ConstructMain PT_Constructor PT_ConstructDoNotKnow PT_ConstructStudent PT_ConstructTeacher DESCRIPCIN Una clase ejecutable. Esta clase contiene el mtodo constructor. Si el tipo es desconocido clase hija de PT_Constructor Si el tipo es un estudiante clase hija de PT_Constructor Si el tipo es un profesor clase hija de PT_Constructor PT_Constructor Methods: construct() hello( )

PT_ConstructMain Methods: main( ) run( )

PT_ConstructDoNotKnow Extends: PT_Constructor Methods: hello ( )

PT_ConstructStudent Extends: PT_Construct Methods: hello ( )

PT_ConstructTeacher Extends: PT_Construct Methods: hello ( )

Pgina 102 de 141

Clases

Como podemos ver, todas las clases hijas contienen el mtodo hello( ), el cual anula al mtodo hello( ) de la clase madre. Esto es importante para ver como trabaja la herencia controlada por constructor. En la clase PT_ConstructMain, nosotros utilizamos el mtodo run( ) para llamar al mtodo constructor( ) de la clase PT_Construct. Class PT_ConstructMain { void run( ) { PT_Constructor constructor; PT_Type type; ; // ** Llama al mtodo PT_ConstructDoNotKnow.hello() constructor = PT_Constructor::construct(PT_Type::DoNotKnow); constructor.hello();

// ** Llama al mtodo PT_ConstructStudent.hello() constructor = PT_Constructor::construct(PT_Type::Student); constructor.hello();

// ** Llama al mtodo PT_ConstructTeacher.hello() constructor = PT_Constructor::construct(PT_Type::Teacher); constructor.hello(); } } Si observamos el mtodo PT_Constructor.construct( ), que abajo se detalla, podemos observar que dependiendo el parmetro que se le pasa al mtodo, l devuelve una de las instancias de las clases hijas. Static PT_Constructor construct(PT_Type type) { switch (Type) {

Pgina 103 de 141

Clases

case (PT_Type::DoNotKnow) : return new PT_ConstructDoNotKnow(); break; case (PT_Type::Student) : return new PT_ConstructStudent(); break; case (PT_Type::Teacher) : return new PT_ConstructTeacher(); break; } }

5.3.

Polimorfismo
Imagina dos objetos diferentes: un coche controlado por control remoto y un helicptero tambin controlado por control remoto. El mismo control remoto es usado para ambos objetos, pero la forma en la que interpretan los mensajes recibidos es diferente. El mismo mensaje: Moverse hacia delante es enviado a ambos objetos. El coche slo debe activar las ruedas para moverse, mientras que el helicptero debe empezar un proceso ms complicado incluyendo el rotor para moverse hacia delante. El objeto del coche y del helicptero son instancias de dos clases diferentes, pero estas dos clases heredan el mtodo de movimiento de la misma clase padre. El mtodo es abstracto en la clase padre, lo cual significa que puede ser implementado indiferentemente en las diferentes clases hijas. Lo que es importante para comprender es que la interpretacin mandada del mensaje descansa en el objeto. Lo que es tambin importantes que necesitas un manejador para acceder a la funcionalidad de los objetos. En este ejemplo el manejador es el control remoto, el cual ilustra que se puede usar el mismo manejador para distintos objetos, pero no puedes usar el mismo manejador par los dos objetos al mismo tiempo. (A menudo un mtodo con el mismo nombre es implementado diferente en otra clase. Pero cada clase conoce como implementar el mtodo en su propia y nica forma. Este concepto es el que se denomina polimorfismo. La idea bsica de polimorfismo es que diferentes mtodos se pueden llamar de acuerdo a contextos diferentes. Una funcin debe tener un tipo de parmetros que determine el tipo de argumento cuando la funcin es llamada o diferentes funciones pueden ser llamadas correspondiendo a diferentes argumentos o el polimorfismo puede implementar alguna herencia. El polimorfismo proporcinala habilidad de escribir programas que son independientes del formulario de los datos a travs de los cuales ellos operan, as permiten un diseo prximo al del mundo real.) Finalmente, una ventaja de la encapsulacin es algo llamado polimorfismo. Simplemente esto significa que ms de una clase de objeto puede (solucionar) una solicitud. El solicitante no conoce y no le preocupa qu clase de objeto ha (solucionado) una solicitud en particular.

Pgina 104 de 141

Clases

5.4.

Encapsulation

En las clases de Axapta, las variables de miembro estn siempre protegidas, tanto es, que no se puede acceder a ellas directamente. Tan solo se puede acceder a ellas dentro de un objeto. Para acceder a las variables debes escribir un mtodo de acceso. De este modo, el mtodo de acceso es la nica interfaz a las variables de miembro. Un ejemplo tpico de un mtodo de acceso para conseguir un valor es: \Classes\CustVendVoucher\InvoiceNum: InvoiceNum InvoiceNum() { return InvoiceNum; } Un ejemplo tpico de un mtodo de acceso para acceder a un valor es \Classes\CustVendVoucher\SetApprovedBy: void SetApprovedBy(EmployeeNum _ApprovedBy) { ApprovedBy = _ApprovedBy; } En lugar de crear un mtodo separado para obtener un valor, puedes hacerlo de igual forma que este ejemplo desde \Classes\Info\DoxRefCreate: boolean DoxRefCreate(boolean _DoxRefCreate = DoxRefCreate) { DoxRefCreate = _DoxRefCreate; return DoxRefCreate; } En el ltimo ejemplo desde que hay un pequeo gasto de memoria y tiempo cuando movemos los datos desde una variable a otra es recomendado usar la tcnica del siguiente ejemplo cuando las variables contiene una enorme cantidad de datos (como contenedores grandes o campos memo): container Code(container _Code = conNull()) {

Pgina 105 de 141

Clases

if (!prmIsDefault(_Code) Code = _Code; return Code; }

5.5.

Recoleccin de objetos
Los objetos necesitan ser asignados o colocados, necesitan tambin ser re asignados para preservarlos en memoria. En otros lenguajes esto est hecho explcitamente, pero en X++ est hecho automticamente. MorphX controla el uso de objetos (el nmero de referencias en un trozo asignado de memoria), y cuando no objetos tienen asignado ninguna porcin de memoria, la memoria es liberada. Este mecanismo es conocido como coleccin de basura. En el ejemplo precedente, asignando null a A2 podra tambin reasignar la memoria asignada y llamar al mtodo finalize en la clase. Asignando Null a A1 podra no reasignar porque A4 hara an referencia a l. Asignando nulas a ambas (A1 y A4) podras reasignar memoria.

Pgina 106 de 141

Desarrollo Cliente/Servidor

Desarrollo Cliente / Servidor


1.
1.1.

Especificar el lugar de ejecucin.


Clases.
Las clases tiene una propiedad RunOn que puede contener estos valores: Cliente (client). Invocado desde (called from). Servidor (server).

Los objetos creados desde la clase residirn donde se haya especificado. Si se escoge called from, el objeto residir en el entorno donde se invoque al constructor (new) (cliente o servidor). Las clases que heredan de otras tambin heredan la propiedad RunOn. Si est establecida a Client o Server no se puede modificar, pero si se trata de Called from s puede modificarse.

1.2.

Mtodos.
Los mtodos estticos de clase as como los mtodos de las tablas pueden cambiar su comportamiento aadiendo el modificador client o server en su declaracin como se muestra en el siguiente ejemplo. server static boolean myMethod() { ... } El mtodo anterior ser siempre ejecutado en el servidor. Por defecto los mtodos estticos de las clases son ejecutados all donde indique la propiedad Run On de la clase en la que se ha declarado el mtodo. Los mtodos dinmicos se ejecutan siempre all donde la clase se ha declarado que resida (a travs de la propiedad Run On). A los mtodos estticos de clase se les puede especificar comportamiento called from indicando en su declaracin que pueden ser ejecutados tanto en el cliente como en el servidor: client server static boolean myMethod() { ... }

Pgina 107 de 141

Desarrollo Cliente/Servidor

Los mtodos de las tablas, se ejecutan desde all donde son llamados, aunque por definicin, los mtodos insert / doInsert, update / doUpdate y delete / doDelete se ejecutan en el servidor.

2.

Tcnicas ptimas de programacin cliente / servidor.


Los objetivos principales a conseguir a este respecto son: Minimizar el trfico entre Servidor y Cliente. Poner la lgica asociada a la interfaz de usuario (GUI) en el Cliente. Por ejemplo: Objetos de tipo FormRun, FormDataSource, todos los FormControls, DialogBox, y OperationProgress (asociados a los formularios) deben residir siempre en el cliente. Elementos asociados a los Informes (como objetos ReportRun) tambin deben residir en el cliente. Poner la lgica asociada a la aplicacin en el Servidor de la Aplicacin. Poner la lgica asociada a la Base de Datos en el Servidor de Base de Datos. Minimizar las llamadas a otros componentes en los bucles locales de la aplicacin. Esto supone evitar, por ejemplo, llamadas a cdigo residente en clientes cuando se est ejecutando un bucle de un proceso batch en el servidor , ya que esto supondra trfico entre cliente y servidor en cada iteracin del bucle. En general, son aceptables algunas llamadas a otros componentes en el comienzo de jobs o a su final.

Pgina 108 de 141

Comunicacin con el usuario

Otras herramientas de desarrollo


1. Las referencias cruzadas.
El sistema de referencias cruzadas fue diseado para mejorar nuestra perspectiva general de los objetos de la aplicacin. El sistema de referencias cruzadas puede responder a preguntas como: 1.- Desde dnde se accede a los campos de una tabla? Para escritura o para lectura? 2.- Desde dnde se accede a los mtodos de una clase o una tabla? 3.- Qu nombres de tipos son utilizados en el sistema? 4.- Qu nombres de variables son utilizados en el sistema? Las referencias cruzadas estn basadas en el cdigo, en las etiquetas, y en la informacin de las propiedades. A travs de ellas, podemos obtener una lista de elementos utilizados en una parte del cdigo o tambin podemos obtener una lista de componentes donde se haga referencia al componente actual. Para poder tener esta informacin disponible, tenemos que seleccionar esta opcin cuando realicemos la configuracin de usuario. Est disponible en la pestaa Desarrollo dentro del grupo General. Si tenemos la casilla de referencias cruzadas seleccionada, podemos construir una lista de elementos cuando compilemos componentes. Para obtener una lista completa de referencias, es necesario compilar toda la aplicacin.

Al tener esta opcin activada, cada vez que compilemos se generaran o actualizaran las referencias cruzadas de aquellos nodos del AOT que compilemos, con lo que siempre dispondremos de las referencias cruzadas actualizadas. Pero al mismo tiempo, la compilacin se volver ms costosa. Por lo tanto, Si se va a desarrollar en Axapta, se recomienda no activar esta casilla y realizar una actualizacin de las referencias cruzadas de todo el AOT de forma peridica. La herramienta para generar las referencias cruzadas de todo el sistema la vamos a encontrar en el men herramientas (tools) / desarrollo (development) / referencias cruzadas, donde accedemos a un dialogo donde podemos indicar que operacin deseamos realizar con las referencias cruzadas. Otro punto de acceso a la herramienta referencias cruzadas mucho ms utilizado est en el men contextual del AOT a travs de la entrada Adds-Ins / Referencia cruzada. A partir de esta entrada es posible no solo actualizar las referencias cruzadas para el nodo sobre el que estamos situados, sino tambin consultar dichas referencias cruzadas segn las distintas modalidades que pasamos a detallar.

Pgina 109 de 141

Comunicacin con el usuario

Si seleccionamos la opcin Nombres, nos muestra una lista de objetos de aplicacin con el nombre del elemento y la posibilidad de ver a que elementos hace referencia el elemento actual.

Si seleccionamos la opcin Ruta de acceso (Path), nos muestra la misma lista pero nombrando la ruta de acceso en el rbol de objetos de la aplicacin del elemento actual.

Y seleccionando el botn Utilizado por nos muestra una ventana, como la mostrada a continuacin, con informacin de los elementos que hacen referencia al elemento actual.

Pgina 110 de 141

Comunicacin con el usuario

2.

Visual MorphXplorer
Utilizaremos el Visual MorphXplorer para visualizar el mdulo de datos de Axapta mediante el dibujo de diagramas de relacin de entidades. Todos los comandos de visualizacin se encuentran disponibles en el men contextual del objeto actual. Utilizaremos las fichas General y Colores para asignar un ttulo a cualquier diagrama y para definir su propia configuracin de color. Antes de comenzar a realizar un diagrama, ser necesario actualizar el sistema de referencias cruzadas, puesto que la informacin para la realizacin de estos diagramas se obtiene de esta herramienta. En el Visual MorphXplorer nosotros podemos representar las relaciones entre tablas con la siguiente informacin: Las relaciones 1:n de la tabla actual. Las relaciones n:1 de la tabla actual. Las clases que utiliza la tabla actual. Los maps en que la tabla actual forma parte. Ejemplo: Diagrama de relacin entre tablas.

CustTable Tabla de clientes 77

pr2

*
AccountNum

AccountNum

CustTable Tabla de clientes 77

CustTrans Transacciones del cliente

pr2

78

pr2

Tambin podemos representar relaciones entre clases. En un diagrama de clases podemos representar: Que clases utiliza la clase activa. Que clases utilizan la clase activa. Que clase es la superclase de la clase activa. Que clases son hijas de la clase activa. Ejemplo: diagrama de relacin entre clases.
RunBase 512 ChequeDelete DialogField

dialogFromChequeNum
Called
43

Called

115

Client

Pgina 111 de 141

Comunicacin con el usuario

2.1.

Nomenclatura del Visual MorphXplorer


A continuacin vamos a especificar la notacin que utiliza MorphXplorer para realizar los diagramas.

2.1.1.

Smbolos para las tablas


Cero, uno o varios registros. Exactamente un registro. Cero o un registro. Tabla utilizada en un map. * Tabla que aparece ms de una vez en el diagrama.

2.1.2.

Smbolos para las clases


De la clase a la superclase. De la clase a la clase que utiliza. * Clase que aparece ms de una vez en el diagrama.

2.2.

Organizar un diagrama en el Visual MorphXplorer

1. Hacer clic con el botn derecho del ratn en cualquier parte libre de la ventana del Visual MorphXplorer. 2. Seleccionar la opcin Organizar el men contextual. Todas las tablas, clases y relaciones son de nuevo organizadas acorde con el algoritmo de mejor situacin. Podemos situar los distintos elementos del grfico seleccionndolos y arrastrndolos hasta la posicin que deseamos. Al realizar esta accin, la herramienta recoloca el resto de objetos del grfico segn este algoritmo de mejor situacin.

2.3.

El zoom en el Visual MorphXplorer


1. Hacer clic con el botn derecho del ratn en cualquier parte libre de la ventana del Visual MorphXplorer. 2. Seleccionar la opcin Zoom y escoger el factor de zoom que deseemos. Hay que indicar que la opcin de zoom solo es vlida para la visualizacin en pantalla del grfico. Para imprimir los diagramas se dispone de una herramienta ms especfica al seleccionar la opcin de imprimir el grfico. A travs del botn Diseo de pgina es posible configurar el tamao de la impresin, impresin multipgina, colores, etc.

Pgina 112 de 141

Comunicacin con el usuario

3.

rbol de jerarqua
El rbol de jerarqua ofrece una vista diferente de los elementos del rbol de objetos. La vista est clasificada por los diferentes tipos de datos. En la imagen de abajo podemos ver el rbol de jerarqua.

A continuacin se muestra un ejemplo, donde podemos ver la definicin de una clase, de qu clase es hija, y que mtodos estn reescritos. De la misma forma tambin podemos ver los campos y mtodos de una tabla.

4.

Herramienta de bsqueda
El aspecto de la ventana de la herramienta Buscar... es similar a Buscar archivos y carpetas de Windows, aunque dispone de algunas optimizaciones especificas para el entorno Axapta.

La ficha Filtro, es una mejora particular de esta herramienta, se utiliza para filtros avanzados del resultado de la bsqueda. Escriba el cdigo X++ en el campo Origen. El cdigo se evala para cada nodo encontrado y debe devolver un valor lgico que ser

Pgina 113 de 141

Comunicacin con el usuario

verdadero si el nodo se va a incluir en el resultado de la bsqueda y falso si no se va a incluir. Se puede detener una bsqueda haciendo clic en el botn Detener (si se encuentra activado) o pulsando Ctrl+Interrumpir. El botn Detener se activa si se buscan slo mtodos (predeterminado) que contengan algo de texto, que utilicen la seleccin y si se han seleccionado algunos de los "nodos raz": AOT, Tablas, Clases, Formularios, Informes, Consultas, Mens, Menu items.

5.
5.1.

Otros
Herramientas de comprobacin de cdigo (Best Practices)
Esta herramienta hace una comprobacin del cdigo desarrollado para ver si se adapta a los estndares de Axapta. La utilizacin de esta herramienta no garantiza que todo el cdigo comprobado cumpla con los estndares de Axapta. Esta herramienta la podemos encontrar en el men contextual del rbol de objetos (AOT), seleccionando la opcin Add-ins / Optimizacin / Comprobar optimizacin. Nosotros podemos ejecutar la opcin Comprobar optimizacin en cualquier nodo el entorno de desarrollo. Basndonos en las directrices descritas en este documento, el resultado nos dar unos consejos sobre como ejecutar nuestro cdigo. A continuacin se detallan una serie de limitaciones de la herramienta: El procedimiento de comprobacin revisa un mtodo cada vez. No tiene perspectiva general. Es un anlisis esttico. No podemos ver la diferencia entre un mtodo del cliente llamado una vez y un mtodo del servidor llamado 1000 veces. No se aprecia como una tabla temporal reside en el servidor como una tabla ordinaria, aunque no debe ser el caso. Actualmente se considera una llamada a queryRun.next() como una llamada al servidor, pero debe considerarse como una llamada al cliente y al servidor, si la queryRun es instanciada desde el cliente y est accediendo a una tabla ordinaria. Tampoco se debe considerar si la tabla temporal reside en cualquier otra parte. No podemos ver si un objeto de una clase llamada es instanciado en un nivel y en otro nivel es pasado como parmetro a un mtodo ejecutable, el cual a su vez llama a mtodos de dicho objeto.

5.2.

Herramientas de comparacin
Esta herramienta realiza comparaciones entre objetos del rbol de objetos. La podemos encontrar en el men contextual del rbol de objetos (AOT), pinchando en la opcin Add-ins / comparar.

Pgina 114 de 141

Comunicacin con el usuario

Para realizar la comparacin entre dos objetos deberemos seguir los siguientes pasos: 1. Seleccionar los dos objetos que deseamos comparar. Tambin podemos seleccionar un slo objeto para realizar comparaciones entre dos diseos o niveles. 2. Abrir el men contextual y escoger la opcin Comparar. 3. Verificar que los objetos seleccionados, son los que queremos para realizar la comprobacin. 4. Pulsar el botn Comparar. Ahora el sistema realizar la comparacin, y ampliar el cuadro de dilogo mostrado anteriormente con dos paneles ms, como se puede ver en la imagen siguiente.

El panel de la izquierda muestra las diferencias entre los dos objetos en una estructura de rbol que puede estar expandido. Y en el panel de la derecha muestra el contenido del nodo actual seleccionado. Las diferencias encontradas son indicadas usando colores, tanto en los iconos de la estructura en rbol como en el contenido del nodo actual. El panel sombreado con las marcas de comprobacin indica que hay diferencias en la hija del nodo. Como podemos ver en el cuadro de dilogo, un objeto est pintado de rojo y el otro objeto est pintado de azul. Cuando existen diferencias el icono del mtodo, control o propiedad etc. est pintado de los dos colores (rojo y azul), si pinchamos sobre este icono nos aparecern en rojo las lneas de cdigo, propiedades o controles que son del objeto rojo, en azul las lneas, propiedades o controles que son del objeto azul y en negro las lneas, controles o propiedades que son idnticos. Si nos aparece el icono con una marca roja, quiere decir que ese mtodo, control o propiedad es del objeto rojo, y si por el contrario aparece con una marca azul, significa que es del objeto azul.

5.3.

Sustitucin
Esta herramienta nos permite cambiar un texto por otro, por ejemplo, cambiar el nombre de un tipo de datos, o el nombre de un campo de una tabla, etc.

Pgina 115 de 141

Comunicacin con el usuario

La podemos encontrar en el men contextual del rbol de objetos (AOT), pinchando en la opcin Add-ins, y despus sustituir sintcticamente.

5.4.

El examinador de tablas
Una vez ya hayamos creado un tipo de interfaz e introducidos datos en una tabla, podemos utilizar el examinador de tablas para facilitar una visin de los datos existentes en la base de datos.

Para abrir el examinador de tablas se siguen los siguientes pasos: 1. Sobre el objeto tabla que queremos ver los datos, abrir el men contextual del rbol de objetos de la aplicacin. 2. Activamos la opcin Add-ins / examinador de tablas. El examinador de tablas nos mostrar los datos de todos los campos de la tabla, excepto los de tipo container. A travs de esta herramienta podemos editar y eliminar registros. Podemos utilizar el examinador de tablas en cualquier sitio donde una tabla sea utilizada como origen de datos: en un formulario, en un informe o en una consulta. Tambin podemos utilizar el examinador de tablas para ver el contenido de las tablas del sistema.

Pgina 116 de 141

Comunicacin con el usuario

Find Open new window...

Find and replace

Used by maps

Used by

Application Hierarchy Tree

Application Object Tree

AOD

Update Crossreference

Crossreference

One

Other Visual MorphXplorer Compare Code Explorer

Comunicacin con el usuario


1. Introduccin
Axapta nos ofrece varias opciones para comunicarnos con el usuario desde la aplicacin. La forma ms comn de interaccin con el usuario es el formulario. Sin embargo, algunas tareas requieren otras formas de comunicacin con el usuario. Este captulo se ha dividido en dos bloques. En el primero, se describirn las posibilidades que nos ofrece el sistema para emitir un mensaje dirigido al usuario. En el segundo, veremos cmo podemos solicitar informacin sencilla al usuario.

2.

Vetanas
En Navision Axapta una de las formas ms fciles para mostrar informacin al usuario es usando una ventana. El comando crea una ventana de cualquier dimensin y posicin en la pantalla, usando el siguiente cdigo: Window x1, y1 [at x2, y2]; Donde x1 es el nmero de caracteres que se pueden poner en la ventana desde la derecha, y1 es el nmero de caracteres que puedes situar en la ventana de arriba abajo. Puedes emplazar la ventana en un lugar de la pantalla que quieras usando la sintaxis at x2, y2. Por ejemplo, un comando de ventana puede ser el siguiente:

Pgina 117 de 141

Comunicacin con el usuario

Window 10,5 at 10,20 Crea una ventana, la cual tiene 10 caracteres de ancho y 5 caracteres de alto. La ventana est situada en la pantalla 10 caracteres a la derecha y 20 caracteres abajo. Nota: En lugar de usar valores positivos tambin se pueden utilizar valores negativos. Esto emplaza en partir de la esquina inferior derecha. En la posicin at, en lugar de la superior izquierda. Si se usan valores negativos para la posicin de la ventana siempre la ventana va a ser creada en la esquina inferior derecha.

3.

Informacin de salida
Axapta nos ofrece distintas posibilidades a la hora de mostrar mensajes al usuario.

3.1.

El sistema InfoLog
El sistema Infolog corresponde a la ventana informativa que utiliza el sistema para mostrar los mensajes de informacin, aviso y error que se generan durante el uso de la aplicacin. En realidad, es ms que una ventana. Se trata de un registro donde se van grabando los diferentes mensajes.

Figura 14. Ventana de mensajes del sistema InfoLog.

3.1.1.

Limitando el nmero de errores presentados en los Infolog

Usa infolog.errorsPerBatch para fijar el nmero mximo de errores. Si el actual nmero de errores excede el mximo, un texto dice que puede haber ms errores de lo que pueden ser mostrados.

3.1.2.

Actualizando el Infolog durante la ejecucin

Usa infolog.viewUpdate() si el Infolog debe ser actualizado durante una ejecucin.

Pgina 118 de 141

Comunicacin con el usuario

a)

EXCEPTION info(Str) Nos permite presentar un mensaje informativo.

Como parmetro de entrada recibe la cadena correspondiente al mensaje. Como valor de retorno, devuelve una excepcin de tipo info. b) EXCEPTION warning(Str) Nos permite presentar un mensaje de aviso.

Como parmetro de entrada recibe la cadena correspondiente al mensaje. Como valor de retorno, devuelve una excepcin de tipo warning. c) EXCEPTION error(Str) Nos permite presentar un mensaje de error. Como parmetro de entrada recibe la cadena correspondiente al mensaje. Como valor de retorno, devuelve una excepcin de tipo error.

d)

boolean checkFailed(Str)

El mtodo CheckFailed retorna un valor booleano y es usado para los avisos (warnings). Como info, warning y error,checkFailed toma tres argumentos: Una string Que es aadida al log (histrico).

Una ruta al sistema de ayuda interno de Axapta Que puede ser usado para abrir el visor de la ayuda y presentar un texto aclaratorio mayor. Este argumento es opcional. Una accin de Infolog Que puede ser usada para iniciar una accin, por Ejemplo para accionar el editor de X++. Este argumento es opcional.

Pgina 119 de 141

Comunicacin con el usuario

3.2.

La sentencia throw
Esta sentencia pertenece al sistema de gestin de excepciones de Axapta, que se describe en un captulo posterior. En estos momentos, nos basta con saber que podemos utilizarla para presentar un mensaje de error al usuario y abortar la ejecucin del cdigo. La sentencia throw error muestra al usuario el mensaje de error especificado en su argumento: throw error("No existen registros");

4.

Informacin de entrada
Adems de los formularios, bsicamente Axapta nos ofrece dos posibilidades para solicitar informacin al usuario.

4.1.

La clase Box
Hay varias limitaciones cuando usamos el comando imprimir. El espacio est limitado, un comando de pausa es necesario para ver lo que se escribe. Una caja (Box) est diseada para arreglar estos problemas. Crear una caja es como esto: Box::info (Text1,Text2,Text3); Tres parmetros son adjuntados para el mtodo de Info en una clase de caja, Text1 es el texto que se muestra en la caja, text2 es el texto que se muestra en la etiqueta de la caja, y el texto 3 es el texto que se muestra como texto de ayuda en el final de la pantalla. No son obligatorios el segundo y tercer parmetro. La caja es usada para mostrar en el ejemplo de arriba es una de las de tipo info, la cual es especificada detrs de los dos puntos. Alternativamente, para crear mensajes de usuario, usa la Stop o la caja de Warning. Los siguientes parmetros son los mismos. Los tipos de cajas mencionadas no son interactivos. Tan solo pueden ser usadas para mensajes para el usuario; no pueden recibir ninguna instruccin del usuario. Examina el AOT y expande las clases y despus el nodo Box para ver una lista de todos los tipos de Box que hay disponibles en X++. Los tipos de cajas que no estn descritos arriba tienen todos algn nmero de botones. El sistema acta de acuerdo con el botn que pulse el usuario. Una caja del tipo YesNO es creada de la siguiente manera: Box::yesno(Text1, DialogButton::No, text2,text3); Como se ha mencionado previamente, hay tres textos el cual solo es obligatorio el primero. En adicin, un cuarto parmetro: DialogButton necesita ser especificado. El parmetro DialogButton controla qu botn se encuentra seleccionado por defecto, antes de que el usuario haga su eleccin. Elige la opcin apropiada para ser ejecutada si el usuario solo selecciona con el botn Enter del teclado.

Pgina 120 de 141

Comunicacin con el usuario

El DialogButton es un Base Enum Ejemplo de cajas: { ; Box::Info(Information \n new line,title,helptext); Print any2int(box::yesno(Is this a yes/no box, dialogbutton::no,title,helptext))at 10,11; Pause; }

Pgina 121 de 141

Comunicacin con el usuario

Tipo de Dilogo

Valor Enumerado/ Cuando utilizarlo Nombre del mtodo InfoBox El usuario debe ser informado de algo, y debe pulsar Ok. El usuario debe ser advertido de algo, y debe pulsar Ok. Se le presenta una eleccin al usuario y debe pulsar S o No. La aplicacin se detiene, posiblemente porque algn error ha ocurrido, o algo serio va a ocurrir, y el usuario debe pulsar Ok. Se le presenta una eleccin al usuario y debe pulsar S, No o Cancelar. Se le presenta una eleccin al usuario y debe pulsar Si a todo, No a todo y Cancelar

Informacin

Advertencia

WarnBox

S/No

YesNoBox

Stop

StopBox

S/No/Cancelar

YesNoCancelBox

S a todo/No a todo/Cancelar YesAllNoallCancelBox

S/No/No a todo/Cancelar

YesNoNoAllCancelarBox Se le presenta una eleccin al usuario y debe pulsar Si, No, No a todo y Cancelar YesYesAllNoCancel Se le presenta una eleccin al usuario y debe pulsar S, S a todo, No, Cancelar Se le presenta una eleccin al usuario y debe pulsar Se le presenta una eleccin al usuario y debe pulsar Aceptar o Cancelar.

S/S a Todo/No/Cancel

S/No/FormularioAxapta

YesNoAxaptaFromBox

Aceptar / cancelar

OkCancelBox

La clase Box hace uso de la clase de sistema DialogBox. Sin embargo, nunca debemos utilizar esta ltima directamente.

4.2.

La clase Dialog
La clase Dialog nos permite presentar al usuario un tipo especial de formulario para que introduzca algunos valores. Tpicamente se utiliza para obtener del usuario determinados parmetros necesarios para la ejecucin de un programa. Esta clase presenta al usuario una ventana estndar.

Pgina 122 de 141

Comunicacin con el usuario

Esta clase se utiliza cuando el dilogo no es muy complejo. Si se hace necesario un dilogo complejo es aconsejable disear un nuevo formulario para este propsito. Internamente, la clase Dialog construye un formulario en tiempo de ejecucin. Los mtodos ms comnmente utilizados de la clase Dialog son: a) Mtodo addField

Se utiliza para aadir un campo al dilogo. Como resultado devuelve un objeto de la clase DialogField. b) Mtodo addGroup Se utiliza para aadir un grupo de campos al dilogo. c) Mtodo run

Este mtodo dibuja el dilogo en la pantalla y permite al usuario que introduzca los valores. Si el usuario pulsa Aceptar el valor de retorno ser true, y si pulsa Cancelar el resultado ser false. De la clase DialogField se utiliza el mtodo value() para asignar valores al campo y recuperar el dato introducido por el usuario. Ejemplo:

Este dilogo puede implementarse como sigue:

boolean myDialog(str fromChequeNum="1000", str numOfCheque="300") { Dialog dialog = new Dialog("@SYS22540");

DialogField DialogAccountId= dialog.addField(typeid(BankAccount));

Pgina 123 de 141

Comunicacin con el usuario

DialogField DialogFromChequeNum= dialog.addField(typeid(BankChequeStartNum)),"@SYS4083"); DialogField DialogNumOfCheque= dialog.addField(typeid(BankChequeQty),"@SYS14578");

DialogAccountId.Value("456"); DialogAccountId.Active(false);

DialogFromChequeNum.Value(FromChequeNum); DialogNumOfCheque.Value(NumOfCheque);

if (dialog.run()) { FromChequeNum= DialogFromChequeNum.Value(); NumOfCheque return true; } return false; } = DialogNumOfCheque.Value();

Pgina 124 de 141

La clase RunBase

La clase RunBase
1. Introduccin
La clase RunBase es una de las clases de sistema ms importantes en Axapta. Nos permite la creacin de clases ejecutables con apenas unas pocas lneas de cdigo. Cuando definimos una clase como hija de RunBase, automticamente estamos heredando toda su funcionalidad, lo que nos facilita mucho la creacin de dichos procesos ejecutables. El funcionamiento bsico de esta clase es el siguiente: 1. Se muestra un dilogo al usuario. Mediante la creacin de una instancia de la clase DialogRunBase. 2. El usuario introduce una serie de valores o parmetros. 3. Se analizan los parmetros. 4. Se ejecuta el proceso a realizar por la clase. Este ser, por tanto, el comportamiento general de cualquier clase que herede de la clase RunBase, las particularidades de cada una de las clases las conseguiremos sobrecargando mtodos.

2.

La clase RunBase. Mtodos principales y su funcin


Para conseguir que una clase ejecutable se comporte como nosotros queremos, debemos sobrecargar los siguientes mtodos: a) ClassDeclaration En este mtodo definiremos la clase y de las variable globales que intervienen en la misma. Ejemplo public class myRunBase extends RunBase { NoYes DialogField ; #DEFINE.CurrentVersion(1) #LOCALMACRO.CurrentList answer #ENDMACRO } answer; dialogAnswer;

Pgina 125 de 141

La clase RunBase

En este mtodo, se define adems una macro que nos va a servir para almacenar los valores que el usuario introduce en el cuadro de dilogo. De este modo, cada vez que ejecutemos la clase, aparecern en el cuadro unos valores predeterminados, que sern los ltimos valores que introdujo el usuario. b) Dialog En este mtodo creamos el dilogo que queremos que se muestre al usuario. La llamada a este mtodo se realiza automticamente desde el mtodo prompt(). Ejemplo Object dialog() { DialogRunbase ; dialog = new DialogRunbase("@MCP254", this); dialogCustFormat = dialog.addField(TypeId(CustFormat)); dialogCustFormat.value(custFormat); dialogFileName = dialog.addField(TypeId(FileNameSave)); dialogFileName.lookupButton(2); dialogFileName.value(fileName); return dialog; } En este ejemplo, se creara un cuadro de dilogo con dos controles, uno de tipo CustFormat y otro de tipo FileNameSave. c) GetFromDialog En este mtodo obtendramos los valores que el usuario introduce en el cuadro de dilogo para asignarlos a las variables globales definidas en ClassDeclaration. Ejemplo private boolean getFromDialog() { ; fileName = dialogFileName.value(); custFormat = dialogCustFormat.value(); return true; } En este mtodo tomaramos los valores de los campos del cuadro de dilogo y lo asignaramos a las variables. d) Pack dialog;

Pgina 126 de 141

La clase RunBase

En este mtodo es donde se almacena la informacin del trabajo que estamos ejecutando en ese momento, para su posterior utilizacin en sucesivas ejecuciones. Ejemplo public container pack() { return [#CurrentVersion, #CurrentList]; } e) UnPack En este mtodo se proporciona al usuario la informacin guardada en la ltima ejecucin, para utilizarla como valores por defecto del cuadro de dilogo. Ejemplo public boolean unpack(container packedClass) { Integer version; ; version = conpeek(packedClass, 1); switch (version) { case #CurrentVersion : [version, #CurrentList] = packedClass; break; default : return false; } return true; } f) Description En este mtodo se realiza una descripcin de la tarea que realiza esta clase. Esto es un estndar, por lo que es aconsejable que en todas las clases que hereden de RunBase exista dicho mtodo. Ejemplo static ClassDescription description() { return "@MCP254"; }

Pgina 127 de 141

La clase RunBase

Se debe poner el texto de descripcin en una etiqueta. De esta forma nos aseguramos que dicha descripcin est disponible en todos los lenguajes soportados por el sistema. g) Run Este mtodo es el ms importante dentro de la clase, ya que constituye el cuerpo principal, es decir, el trabajo o la tarea que vamos realizar. Ejemplo void run() { if (answer) // Instrucciones; else // Instrucciones; } Donde ejecutaramos unas instrucciones u otras en funcin de los valores introducidos por el usuario en el cuadro de dilogo. h) Main Este mtodo es el primero que se ejecuta en cualquier clase ejecutable, y desde l se llama a los dems mtodos. Es por tanto, el mtodo que controla la ejecucin de la clase. Se trata de un mtodo esttico que siempre presenta la estructura que se muestra en el ejemplo siguiente. Ejemplo static void main(Args a) { MyClass ; myClass = new MyClass(); if (myClass.prompt()) myClass.run(); } myClass;

3.

La clase RunBaseBatch
La clase RunBaseBatch es una clase que hereda de la clase RunBase, cuya principal caracterstica, es que permite la creacin de procesos de ejecucin por lotes (batch). Por lo tanto, utilizaremos la clase RunBase en aquellas tareas que no necesiten procesamiento por lotes y la clase RunBaseBatch en aquellas tareas que si lo necesiten.

Pgina 128 de 141

La clase RunBase

La clase RunBaseBatch es una clase utilizada como base para la realizacin de clases que lleven consigo funcionalidad de alto nivel. Este tipo de clases tiene normalmente una estrecha relacin con funciones de men y pueden ser activadas directamente por el usuario. Si queremos crear una clase ejecutable por lotes, debemos crearla de forma que herede de RunBaseBatch. Los mtodos que debemos sobrecargar en este tipo de clases son los mismos que en el caso de las clases RunBase, pero adems debemos sobrecargar el mtodo siguiente: a) CanGoBatch Este mtodo aade un botn al cuadro de dilogo que permite la ejecucin de la tarea a realizar mediante un proceso por lotes. La codificacin del mtodo es muy sencilla, simplemente debemos devolver un valor verdadero si queremos permitir que el proceso pueda ser ejecutado mediante un proceso batch. Ejemplo protected boolean canGoBatch() { return true; }

4.

La clase RunBaseReport
La clase RunBaseReport es una clase que tambin hereda de la clase RunBase, cuya principal caracterstica es que permite la creacin de informes personalizados mediante cdigo. Utilizaremos esta clase cuando necesitemos un informe que presente al usuario un cuadro de dilogo especfico para la introduccin de datos a dicho informe. Primero debemos crear en el Arbol de Objetos de la Aplicacin (AOT), el diseo del informe. Seguidamente, debemos crear la clase RunBaseReport que se encargar de dotar de funcionalidad adicional a ese informe. Los mtodos que debemos sobrecargar en esta clase son los mismos que en el caso de las clases RunBase, pero adems debemos sobrecargar los mtodos siguientes: a) InitParmDefault Este mtodo inicializa los parmetros del informe con valores por defecto. Debemos sobrecargarlo, solamente cuando queramos modificar dichos parmetros por defecto. Si sobrecargamos el mtodo, debemos realizar la llamada al mtodo super(). Como ejemplo mostramos el mtodo InitParmDefault de la clase CustInvoiceVolumeReport. Ejemplo void initParmDefault() { ; reportBy = AccountVATNum::VATNum;

Pgina 129 de 141

La clase RunBase

fromDate toDate minAmount super (); } b)

= mkdate(1, 1, year(systemdateget())); = systemdateget(); = 500000;

LastValueElementName Este mtodo se utiliza para enlazar el diseo del informe creado en el Arbol de Objetos de la Aplicacin con la clase RunBaseReport. Como ejemplo mostramos el mtodo LastValueElementName de la clase CustInvoiceVolumeReport. Ejemplo private ReportName lastValueElementName() { return reportStr(CustInvoiceVolume); }

Pgina 130 de 141

Contenedores y sus funciones

Maps
1. Definicin
En ocasiones podemos encontrar tablas en la aplicacin que sean muy similares. stas pueden tener varias columnas que contengan el mismo tipo de informacin, pero cuyo nombre sea diferente. Tambin puede ser usual tener clases que procesen de igual forma datos de distintas tablas. Si utilizamos el mismo nombre para las columnas, podemos reutilizar el cdigo que procese los datos de distintas tablas, pero hay que procurar mantener nombres coherentes a las columnas para hacer la aplicacin ms fcil de mantener. MorphX posee una poderosa caracterstica llamada map que permite cubrir estos dos requerimientos. Un map permite acceder a campos de distintas tablas si los campos son de tipos similares, aunque tengan nombres distintos. Cada tabla puede ser objeto de un map. Normalmente, si se tiene acceso a una tabla desde distintos maps, cada map accede a distintos subgrupos de campos de la tabla. Supongamos un map Address que puede ser utilizado para acceder a dos tablas: CompanyInformation y CustomerAddress. Supongamos que las tablas contienen campos similares a los siguientes:

Campo CompanyInformation Name Address1 Campo CompanyInformation Address2 ZIPCode

en Campo CustomerAddress CustomerName Address en Campo CustomerAddress Address1 ZIPCode

en Campo en map Address

Name Street en Campo en map Address

City PostalCode

Para acceder a las tablas CompanyInformation y CustomerAddress a travs del map tenemos que utilizar como nombre del campo los definidos por el map.

2.

Creacin.
El proceso de creacin de un map es muy similar al de una tabla. Desde el men contextual Tablas pulsamos el botn New y Map.

Pgina 131 de 141

Contenedores y sus funciones

2.1.

Campos.
Al igual que en las tablas, en los maps tenemos una nodo Fields desde el cual podemos aadir campos al map, as como un nodo Group para definir grupos de campos.

2.2.

Mappings contra tablas.


Para definir como redirigir los accesos de los campos al map, pulsamos botn derecho sobre el nodo Mappings y seleccionamos New Mapping. MorphX aadir una lnea debajo de dicho nodo vaca. Si pulsamos sobre las propiedades del nuevo objeto podemos seleccionar la tabla para la cual vamos a definir el Mapping. La siguiente ilustracin muestra un el map de direcciones (AddressMap) entre una serie de tablas:

Para asociar los campos del map a los de la tabla expandimos cualquiera de las tablas. Tendremos una entrada por cada campo definido en el map. Abrimos las propiedades de cualquiera de ellos y establecemos la asociacin: Si repetimos el proceso para cada una de las tablas ya tenemos definido el map.

2.3.

Mtodos en maps
En un map podemos encontrar los mismos mtodos que en las tablas, y tambin es posible definir mtodos nuevos. Para utilizar estos mtodos ser necesario referenciar al map, al igual que referenciamos a las tablas, con la particularidad de que un map no contiene informacin. Para que el map contenga informacin, y por tanto tenga utilidad su uso, primero hay que asignarle la informacin de una tabla que tenga definido un mapping en el map. Es decir, de alguna forma, se tratara de realizar una conversin de los datos de la tabla al mapping (se realiza con una simple asignacin entre variables), y utilizar al map para trabajar con estos datos.

Pgina 132 de 141

Acceso a claves de funcin desde el cdigo

Acceso a claves de funcin desde el cdigo


El comportamiento de las claves de funcin, est regulado por la clase de sistema DictFeatureKey. Por lo tanto, si queremos acceder a una clave de funcin desde cdigo, deberemos crearnos una instancia de dicha clase. Para ello utilizaremos el constructor. Ejemplo DictFeatureKey fk; ; fk = new DictFeatureKey(Featurekeynum(BOMVersion)); En el nodo Documentacin de sistema del AOT encontraremos ms informacin acerca de esta clase. En este captulo vamos a describir nicamente los mtodos ms utilizados: a) Mtodo enabled() Este mtodo nos permite comprobar si la clave de funcin est activada a nivel de sistema. b) Mtodo rights() Este mtodo nos permite averiguar si el usuario tiene habilitada la clave de funcin. Ejemplo: if (fk.rights() == AccessType::NoAccess)

Pgina 133 de 141

Gestin de excepciones

Gestin de excepciones
MorphX tiene construido un sistema de manejo de excepciones. Esto permite capturar errores durante la ejecucin de un programa, y controlar el comportamiento del sistema ante ellos. Para utilizar el manejo de excepciones, se tienen que especificar las sentencias a controlar mediante el uso de try y catch. Toda sentencia try tiene asociada al menos una sentencia catch, donde las excepciones son capturadas. Cuando es lanzada una excepcin dentro de una transaccin, la transaccin es automticamente abortada. Este comportamiento se aplica tanto a las excepciones definidas por el usuario como a las propias del sistema.

1.

Sentencia try / catch.

A veces cuando escribimos una porcin de cdigo, t conoces que se pueden dar ciertos errores (excepciones). Para prevenir al sistema de un bloqueo cuando se produce una excepcin, se pueden usar dos comandos que identifican y renen las excepciones. Puedes decirle al sistema que de un mensaje de error al usuario ayudndole a corregir el error, o puedes decirle al sistema que reintente la operacin. Los dos comandos que se pueden utilizar son el try y catch. Ejemplo: Quieres crear un nuevo cliente, pero quieres liberar el nmero en la secuencia numrica, si no tienes xito salvando el cliente. Adems de esto no permites un cliente con un nmero menor de 500. Static void TTSStatement (args a) { CustTable custtable; NumberSeq numberseq; Num Number; ; try { tts begin; numberSeq = NumberSeq::newGetNumFromCode (Cust_1); number = numberSeq.num(); custTable.CustGroup = 20; custTable.Name = Martin Hansen; custTable.AccountNum = number; custTable.insert(); if (number < 500) { throw (exception::Error) }

Pgina 134 de 141

Gestin de excepciones

catch (exception::Deadlock) { numberSeq.abort(); retry; } } Como pueden ocurrir multitud de distintas exceciones, un nmero de Enums excepciones estn disponibles en el kernel:

Exception
Exception::info Exception::warning

Description
Muestra un mensaje de informacin al usuario.

Indica que se ha producido una situacin excepcional. El usuario deber llevar a cabo alguna accin pero las consecuencias no son fatales. Indica que existe un bloqueo en la base de datos debido a que diversas transacciones estn esperandose unas a otras. Normalmente no requieren intervencin por parte del usuario, y solo ser necesario reintentar la operacin. Indica que ha ocurrido un error fatal y que la transaccin ha sido abortada. Usada para mostrar errores internos de desarrollo de Navision Axapta. Indica que el usuario ha pulsado Break o CTRL+C. Ha ocurrido un error en la clase DDE-kernel. (Se ha recibido una comunicacin de error de DDE desde el sistema operativo).

Exception::deadlock

Exception::error Exception::internal Exception::break Exception::dderror

2.

Sentencia throw
Tambin es posible que nosotros lancemos excepciones en nuestro cdigo al detectar algn error en el proceso. Esto es posible a travs de la sentencia throw: Throw error (Mensaje del error); Se puede obtener una descripcin ms amplia del cdigo en la Ayuda en lnea de Axpata, en el Manual del Desarrollador de Axapta. sta sentencia puede incluirse en cualquier mtodo de la aplicacin, aunque es usual incluirlo en una seccin try, de manera que podamos controlar totalmente el comportamiento del sistema ante la excepcin producida. Ejemplo: try

Pgina 135 de 141

Gestin de excepciones

{ throw exception::error; // statements } catch (exception::error){ // React on the error-exception }

Las excepciones definidas por el sistema vienen recogidas en el enumerado exception, y pueden ser: Info Warning Muestra un mensaje de informacin al usuario. Indica que se ha producido una situacin excepcional. El usuario deber llevar a cabo alguna accin pero las consecuencias no son fatales. Indica que existe un bloqueo en la base de datos debido a que diversas transacciones estn esperandose unas a otras. Normalmente no requieren intervencin por parte del usuario, y solo ser necesario reintentar la operacin. Indica que ha ocurrido un error fatal y que la transaccin ha sido abortada. Indica que el usuario ha pulsado BREAK o CTRL+C. Ha ocurrido un error en la clase DDE-kernel. (Se ha recibido una comunicacin de error de DDE desde el sistema operativo).

Deadlock

Error

Break Ddeerror

3.

Retry
Inserta el comando retry en la seccin del catch para decirle al sistema que ejecute la seccin del try de nuevo. Usa el retry con precauciones para no crear un bucle infinito. El comando es usado tpicamente para situaciones de bloqueo.

Pgina 136 de 141

Acceso a men items desde cdigo

Acceso a men items desde el cdigo


Para ejecutar un men item desde cdigo X++, tenemos que utilizar la clase de sistema MenuFunction. Esta clase de sistema representa el nodo MenuItems del rbol de objetos de la aplicacin. Un objeto MenuFunction representa una interfaz de otro objeto de aplicacin Axapta. Este objeto proporciona un camino fcil para acceder y ejecutar cualquier formulario, informe, trabajo, clase o consulta. Para hacer referencia a un objeto de la aplicacin utilizamos el objeto MenuFunction. Para crear un objeto de este tipo, necesitaremos indicar como parmetros al constructor qu tipo de menu item es (display, output o action), y el nombre del objeto (nombre con el que aparece en el AOT (para esto ltimo es interesante utilizar las clases del sistema que convierten nombres de objetos a cadenas como se muestra en el ejemplo). Despus se crea el objeto en cuestin a travs del mtodo create del menu item, que nos devolver el objeto, y lo podremos asignar a una variable para manejarlo. El mtodo create del menu item require que se le pase como parmetro un objeto args, que servir para pasar los parmetros al objeto recin creado. Modificando los valores de la variable args antes de crear el objeto conseguiremos enviar los parmetros que nos interesen al objeto recin creado. Por ltimo solo nos queda ejecutar el objeto recin creado. Ejemplo: Utilizacin de un objeto MenuFunction para crear y ejecutar un informe. { TaxReportVoucher taxReportVoucher;

MenuFunction mf; ReportRun Report; Args A = new Args();

. . . . // Seleccin del registro taxReportVoucher . . . . Nombre del informe // Creacin de un objeto MenuFunction mf = new MenuFunction(ReportStr(TaxReporting), MenuItemType::Output); Tipo de menu item

//Obtener los argumentos que le vamos a pasar al informe. A.caller(this); A.record(taxReportVoucher); Report = mf.create(A); Report.run(); }

Pgina 137 de 141

Indicacin de operaciones en ejecucin

Indicacin de operaciones en ejecucin


1. Informacin de sistema ocupado.
Cuando ejecutamos un objeto, un reloj de arena o una barra de progreso nos indican que la ejecucin se est realizando. Si sabemos que la ejecucin de nuestro proceso va a tardar un tiempo, deberemos informrselo al usuario. Para ello utilizaremos el mtodo startLengthyOperation, de la clase Global. Este mtodo cambiar el cursor de Windows al utilizado para operaciones costosas (reloj de arena). El reloj de arena permanecer en la pantalla hasta que el sistema detecte que el usuario puede realizar operaciones o se haga una llamada explcita al mtodo endLengthyOperation de la clase Global.

2.

Informacin del progreso de una operacin.


Si durante la ejecucin de un proceso queremos mostrar una barra de progreso, dentro de cualquier mtodo nos creamos una instancia de la clase sysOperationProgress, pasndole el nmero de barras que queremos que nos muestre. Esta barra de progreso la podemos personalizar utilizando los mtodos que tiene esta clase. Por ejemplo, si al cuadro de dilogo que muestra cuando creamos la barra de progreso queremos pasarle un ttulo utilizaremos el mtodo caption de dicha clase. Si queremos aadirle una animacin al cuadro de dilogo, utilizaremos el mtodo setAnimation pasndole como parmetro la ruta de acceso donde vamos a encontrar la animacin. Axapta dispone de un nmero de animaciones estndar para utilizar en estas propiedades codificadas a travs de macros. Para indicar cual va a ser el total de cuenta de cada barra se utiliza en mtodo setTotal, al que se le pasa como primer parmetro el total de incrementos de la barra, y el segundo a qu barra de progreso nos referimos. Este segundo parmetro por defecto vale 1, con lo que si solo tenemos una barra no ser necesario este segundo parmetro. Tambin le podemos indicar en cuanto debe incrementar la barra cada vez, para ello utilizaremos el mtodo incCount, este mtodo tiene como valores por defecto 1, as que si slo tenemos una barra de progreso, y queremos que cada vez incremente en 1, tan slo haremos una llamada al mtodo sin pasarle ningn parmetro. A continuacin se presenta un ejemplo de creacin de una barra de progreso: { . . . progress = new SysOperationProgress(2); progress.setCaption("@SYS26056"); progress.setTotal(totalTables+1, 1); progress.setAnimation(#AviFileCopy); . . .}

Pgina 138 de 141

Indicacin de operaciones en ejecucin

xClases
1. X-Classes
En el nodo de clases, debajo del nodo de System Documentation (documentacin del sistema) encontraremos las X-Clases. Las X-Clases se proporcionan con una variedad de mtodos para ejecutar formularios, informes, consultas, ceacin de tablas y dems. Varias de estas clases son heredadas de varias de las clases de sistema y extendidas con funcionalidad aadida.

X-CLASS xApplication

SYSTEM CLASS Aplicacin

XclassFactory

ClassFactory

Xcompany

Company

Xinfo

Info

Xrecord

Xref

Xsession

Session

DESCRIPTION Retorna informacin concerniente a la Compaa, Systemdate, etc... Los mtodos pueden ser sobreescritos. Son usados cuando quieres ejecutar formularios, informes o consultas. Los mtodos pueden ser sobreescritos. Retornando informacin de la compaa Los mtodos pueden ser sobrescritos. Usados para mostrar informacin, avisos y mensajes de error al usuario. Los mtodos pueden ser sobreescritos. Cuando ests creando una nueva tabla, la tabla hereda ste mtodo de sta clase. Los mtodos no pueden ser sobreescritos. Usada para actualizar las referencias, cuando compilan un objeto. Retorna informacin concerniente a la fecha hora usuario y dems del Login. Los mtodos pueden ser sobreescritos.

Cuando intentas abrir las X-Classes no podrs abrir el cdigo, pero en lugar de ello un archivo mostrar informacin acerca el mtodo especfico o las clase.

Pgina 139 de 141

Indicacin de operaciones en ejecucin

2. Class Factory

La clase xClassFactory contiene mtodos para ejecutar formularios, consultas e informes. Usa esta clase para ejecutar formularios, informes y consultas. El sistema usa esta clase para sobrescribir la funcionalidad de la ejecucin de los formularios, informes o consultas. Por ejemplo puedes mostrar una caja de informacin (Info Box) con el nombre del formulario, cada vez que el formulario es ejecutado.

3. The Global Class

La clase global es la clase que contiene las funciones estndar en el ambiente de desarrollo de X++. Si quieres aadir o cambiar un mtodo al mbito global de Navision Axapta es hecho en esta clase. S cuidadoso de no cambiar la funcionalidad de este mtodo ya que tiene influencia sobre Navision Axapta como plan global.

Personalizando formularios Lookup


Para crear un formulario de forma que aparezca como un lookup, en lugar del que se crea automticamente con el grupo de campos AutoLokup deberemos seguir estos pasos: Tendremos que anular el mtodo LookUp del control del campo que queremos que muestre el LookUp. Ahora lo que deberemos escribir en este mtodo es lo siguiente, siendo el Nombre del formulario el nombre del formulario que mostrar los datos del campo que nos interesa. public void lookup() { FormRun newPopup; Args ; args.name(formstr(Nombre del formulario)); newPopup = classFactory.formRunClass(args); newPopup.init(); this.performFormLookup(newPopup); } args = new Args();

Pgina 140 de 141

Indicacin de operaciones en ejecucin

Lo segundo que haremos es crear un formulario que nos muestre la informacin que queremos que aparezca en el lookup y este formulario tiene que tener la propiedad Frame del diseo como "Border" para ser visto como lookup . Para que este valor nos sea devuelto, y se quede la informacin en el formulario principal, debemos anular el mtodo Init del formulario, y la forma en la que lo haremos ser la siguiente (siendo el nombre del control el control del campo que queremos que nos devuelva al formulario principal): public void init() { super(); element.selectMode(element.control(Control::nombre del control);

Funciones Generales
Funciones Matemticas: abs, acos, asin, atan, decround,exp,frac,power,trunc. Funciones de conversin: any2date, any2int, str2int, str2date, etc. Conseguir identificadores: ClassIdGet, ClassNum, FeatureKeyNum, FieldNum, etc. Manipulacin de datos del container: ConDel, ConFind, ConIns, ConPeek, etc. Funciones financieras: Cterm, Dbd, Dg, Fv, Idg, Syd, etc. Informacin acerca del nuevo ambiente: CurExt, CurUserId, SessionId. Funciones de fechas: DayName, DayOfMth, DayOfWk, SystemDateGet, SystemDateSet,etc Funciones string: StrAlpha, StrCmp, StrDel, StrFind, StrFmt, StrKeep, StrLwr, StrPrompt, StrRem.

Pgina 141 de 141