10.05.2013 Views

Manual de programador _ControlsSAP.pdf

Manual de programador _ControlsSAP.pdf

Manual de programador _ControlsSAP.pdf

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>ControlsSAP</strong> Framework<br />

<strong>Manual</strong><br />

Operativo<br />

V2007.9<br />

Por Oliver Parra


<strong>ControlsSAP</strong> Framework ®<br />

Índice <strong>de</strong> Contenidos<br />

1 Introducción a <strong>ControlsSAP</strong>.................................................................4<br />

1.1 Prerrequisitos........................................................................................................... 5<br />

1.2 Método <strong>de</strong> trabajo.................................................................................................... 5<br />

2 Objetos <strong>de</strong> negocio..............................................................................6<br />

2.1 Definición <strong>de</strong> Objeto <strong>de</strong> Negocio............................................................................... 6<br />

2.2 Creación <strong>de</strong> un objeto maestro (SAPObject).............................................................. 7<br />

2.3 Creación <strong>de</strong> los objetos <strong>de</strong>talle (SAPLines)................................................................ 8<br />

2.4 Utilización <strong>de</strong> un objeto <strong>de</strong> negocio........................................................................ 10<br />

2.5 Tipo <strong>de</strong> validaciones <strong>de</strong>finidas................................................................................ 11<br />

2.6 Eventos................................................................................................................... 13<br />

2.6.1 Altas/Modificaciones...................................................................................... 14<br />

2.6.2 Eliminaciones................................................................................................. 15<br />

3 Diseño <strong>de</strong> pantallas visuales..............................................................16<br />

3.1 Controles................................................................................................................ 16<br />

3.1.1 SAPTextBox.................................................................................................... 17<br />

3.1.2 SAPListBox...................................................................................................... 17<br />

3.1.3 SAPComboBox................................................................................................ 19<br />

3.1.4 SAPGrid.......................................................................................................... 21<br />

3.1.5 SAPTreeSearch............................................................................................... 24<br />

3.1.6 SAPAttachments............................................................................................. 25<br />

3.2 Pantallas................................................................................................................. 26<br />

3.2.1 FormSAP......................................................................................................... 26<br />

3.2.2 FormEditSAP................................................................................................... 27<br />

3.2.3 FormWizard.................................................................................................... 30<br />

3.2.4 FormSAPAlta.................................................................................................. 31<br />

3.2.5 FormApplication............................................................................................. 32<br />

4 Formulario <strong>de</strong> edición (FormEditSAP)................................................34<br />

4.1 Diseño <strong>de</strong>l formulario............................................................................................. 34<br />

4.2 Configurar el formulario.......................................................................................... 35<br />

4.3 Entrada/Salida <strong>de</strong> datos.......................................................................................... 37<br />

4.4 Trabajar con las grids.............................................................................................. 38<br />

5 Impresiones........................................................................................40<br />

5.1 Objeto Report......................................................................................................... 40<br />

5.2 Tipo <strong>de</strong> conexión .................................................................................................... 42<br />

5.3 Versiones Crystal Reports....................................................................................... 42<br />

5.4 Visor <strong>de</strong> informes.................................................................................................... 43<br />

5.5 Configurar informes en formularios........................................................................ 43<br />

2


<strong>ControlsSAP</strong> Framework ®<br />

6 Mensaje <strong>de</strong> sistema...........................................................................48<br />

6.1 Mensajes <strong>de</strong> dialogo............................................................................................... 48<br />

6.2 Mensajes en la barra <strong>de</strong> estado .............................................................................. 49<br />

6.3 InputBox................................................................................................................. 49<br />

7 Autorizaciones...................................................................................51<br />

7.1 Definición............................................................................................................... 51<br />

7.2 Creación................................................................................................................. 52<br />

8 Parámetros.........................................................................................53<br />

8.1 Creación <strong>de</strong> parámetros.......................................................................................... 53<br />

8.2 Utilización <strong>de</strong> parametros....................................................................................... 55<br />

9 Módulos <strong>de</strong> trabajo............................................................................58<br />

9.1 Creación <strong>de</strong> un módulo........................................................................................... 59<br />

9.2 Creación <strong>de</strong> los Menús............................................................................................ 59<br />

9.3 Creación <strong>de</strong> la base <strong>de</strong> datos................................................................................... 60<br />

9.4 Control <strong>de</strong> versiones............................................................................................... 62<br />

9.5 Creación <strong>de</strong> parámetros.......................................................................................... 62<br />

9.6 Arranque <strong>de</strong> un módulo <strong>de</strong> trabajo......................................................................... 63<br />

10 Integración......................................................................................66<br />

10.1 Estilo 8.8................................................................................................................. 66<br />

10.2 Fuente, tamaño <strong>de</strong> letra y color <strong>de</strong> las pantallas..................................................... 67<br />

10.3 Textos Dinámicos (Control + Doble-Click)................................................................ 67<br />

10.4 Menús para SAP Business One................................................................................ 68<br />

11 Database.........................................................................................69<br />

11.1 Tablas, campos, índices........................................................................................... 69<br />

11.1.1 Campos.......................................................................................................... 69<br />

11.1.2 Índices............................................................................................................ 70<br />

11.2 Vistas...................................................................................................................... 70<br />

11.3 Procedimientos almacenados................................................................................. 70<br />

11.4 Sentencia SQL......................................................................................................... 70<br />

11.5 Categorías, consultas pre<strong>de</strong>finidas, búsquedas formateadas................................... 71<br />

11.5.1 Consultas pre<strong>de</strong>finidas................................................................................... 71<br />

11.5.2 Búsquedas formateadas................................................................................. 71<br />

3


<strong>ControlsSAP</strong> Framework ®<br />

1 Introducción a <strong>ControlsSAP</strong><br />

<strong>ControlsSAP</strong> es un Framework <strong>de</strong> <strong>de</strong>sarrollo para crear aplicaciones en SAP Business One 2007<br />

utilizando la plataforma <strong>de</strong> Microsoft .NET Framework 2.0, incluyendo métodos para:<br />

• Replicación <strong>de</strong> controles y pantallas con la funcionalidad y aspecto <strong>de</strong> SAP B1,<br />

sin necesidad <strong>de</strong> utilizar la UI.<br />

• Fácil utilización y creación <strong>de</strong> objetos <strong>de</strong> negocio no contemplados en la DI <strong>de</strong><br />

SAP Business One.<br />

• Facilidad en el mantenimiento <strong>de</strong> objetos <strong>de</strong> negocio utilizando formularios <strong>de</strong><br />

edición propios.<br />

• Conjunto <strong>de</strong> herramientas para la creación en el arranque <strong>de</strong>: tablas, campos,<br />

búsquedas formateadas, consultas pre<strong>de</strong>finidas, vistas, etc. y<br />

parametrizaciones necesarias para el funcionamiento <strong>de</strong> nuestras aplicaciones.<br />

• Control <strong>de</strong> versiones.<br />

• Impresiones con Crystal Reports.<br />

• Integración completa <strong>de</strong> pantallas realizadas en .NET <strong>de</strong>ntro <strong>de</strong> SAP Business<br />

One.<br />

• Etc.<br />

Dado a las numerosas carencias proporcionadas por la UI, la mejor forma <strong>de</strong> trabajar será la <strong>de</strong><br />

utilizar el AddOn2 Framework para trabajar con pantallas existentes <strong>de</strong> SAP. Y utilizaremos el<br />

framework <strong>de</strong> <strong>ControlsSAP</strong> para la creación <strong>de</strong> nuevas pantallas, ya que este posee un conjunto<br />

<strong>de</strong> controles y pantallas que replican a los proporcionados por la UI, pero con toda la<br />

potencialidad <strong>de</strong> .NET y con la posibilidad <strong>de</strong> po<strong>de</strong>r añadir a <strong>de</strong>más controles propios sin ningún<br />

tipo <strong>de</strong> problema.<br />

4


<strong>ControlsSAP</strong> Framework ®<br />

1.1 Prerrequisitos<br />

Para seguir el presente manual, y <strong>de</strong>sarrollar con <strong>ControlsSAP</strong> Framework, es preciso tener<br />

instalado:<br />

• Sistema Operativo Windows XP/Server 2003<br />

• SAP Business One 2007 + SDK<br />

• Visual Studio 2005 + .NET Framework 2.0<br />

• SQL Server 2000/2005<br />

Adicionalmente se <strong>de</strong>berá instalar:<br />

• Librerías <strong>de</strong> Crystal Reports (para po<strong>de</strong>r visualizar informes)<br />

• Librerías DevExpress 2008 (para po<strong>de</strong>r diseñar formularios con varios controles)<br />

• AddOn2 Framework (para la integración <strong>de</strong>l proyecto en SAP Business One)<br />

1.2 Método <strong>de</strong> trabajo<br />

La forma <strong>de</strong> trabajar con <strong>ControlsSAP</strong> será la <strong>de</strong> crear módulos <strong>de</strong> trabajo. Estos módulos serán<br />

librerías (dll’s) que podremos añadir en un proyecto cliente. De esta manera conseguiremos<br />

reutilizar el mismo código para varios clientes con las mismas necesida<strong>de</strong>s.<br />

Los módulos constarán <strong>de</strong>:<br />

• Objetos que se <strong>de</strong>ben crear en la base <strong>de</strong> datos (tablas, vistas, campos,<br />

búsquedas formateadas, etc.)<br />

• Opciones <strong>de</strong> menú<br />

• Lista <strong>de</strong> Parámetros<br />

• Autorizaciones para los formularios<br />

• Numero <strong>de</strong> versión <strong>de</strong> datos<br />

5


<strong>ControlsSAP</strong> Framework ®<br />

2 Objetos <strong>de</strong> negocio<br />

Antes <strong>de</strong> crear cualquier pantalla necesitaríamos saber que objetos <strong>de</strong> negocio va a incluir<br />

nuestra aplicación y que relación van a tener entre ellos. Esta es la mejor manera <strong>de</strong> encapsular<br />

nuestro código y po<strong>de</strong>rlo reutilizar mas a<strong>de</strong>lante en diferentes proyectos, gracias a que todo<br />

nuestro código se basará en objetos.<br />

Con esto conseguiremos <strong>de</strong>finir en cada módulo una pequeña Data Interface (DI) que se podrá<br />

intercambiar entre diferentes Partners.<br />

2.1 Definición <strong>de</strong> Objeto <strong>de</strong> Negocio<br />

Podremos <strong>de</strong>finir diferentes tipos <strong>de</strong> objeto:<br />

• Objetos maestros<br />

• Objetos <strong>de</strong>talle<br />

Cada uno <strong>de</strong> ellos trabajará con una tabla <strong>de</strong> la base <strong>de</strong> datos. Un objeto maestro podrá<br />

contener cero o varios objetos <strong>de</strong>talle que serán sus líneas.<br />

.<br />

O. Maestro<br />

O. Detalle<br />

O.Detalle<br />

O.Detalle<br />

6<br />

D.B.


<strong>ControlsSAP</strong> Framework ®<br />

2.2 Creación <strong>de</strong> un objeto maestro (SAPObject)<br />

Para crear un objeto maestro <strong>de</strong>beremos heredar <strong>de</strong> la clase <strong>ControlsSAP</strong>.SAPObject. Solo por<br />

tenerla <strong>de</strong> base ya dispondremos <strong>de</strong> una serie <strong>de</strong> métodos y propieda<strong>de</strong>s para interactuar con<br />

la base <strong>de</strong> datos.<br />

Estos métodos serán los mismos que proporcionan los objetos <strong>de</strong> la DI por lo que ya <strong>de</strong>berían<br />

<strong>de</strong> ser <strong>de</strong> sobras conocidos.<br />

Object:<br />

<br />

Methods:<br />

+Add<br />

+GetByKey<br />

+Remove<br />

+Update<br />

…<br />

Properties:<br />

Browser<br />

<br />

…<br />

Aña<strong>de</strong> el objeto en la base <strong>de</strong> datos.<br />

Obtiene los datos <strong>de</strong>l objeto por su clave.<br />

Elimina el objeto <strong>de</strong> la base <strong>de</strong> datos.<br />

Modifica los datos <strong>de</strong>l objeto.<br />

Permite navegar entre sus diferentes registros.<br />

Los diferentes tipos <strong>de</strong> Líneas que pue<strong>de</strong> tener<br />

el objeto.<br />

Inicialmente necesitaremos implementar 3 métodos para crear un objeto cabecera:<br />

• Constructor: don<strong>de</strong> le indicaremos la Company y la tabla <strong>de</strong> la base <strong>de</strong> datos <strong>de</strong><br />

la que obtendrá los datos.<br />

• InicializeLines: Método don<strong>de</strong> inicializaremos todos los objetos <strong>de</strong> línea <strong>de</strong><br />

nuestro objeto <strong>de</strong> negocio y <strong>de</strong>más variables que podamos tener. Para<br />

inicializar las clases <strong>de</strong> líneas <strong>de</strong>beremos llamar al método DestroyLines().<br />

• ModifyingObject: Utilizaremos este método para modificar la estructura<br />

interna <strong>de</strong> nuestro origen <strong>de</strong> datos antes <strong>de</strong> empezar a trabajar con sus datos.<br />

Des<strong>de</strong> aquí podremos:<br />

o Añadir un campo mas a nuestra estructura <strong>de</strong> datos con AddField().<br />

o Indicar que un campo será <strong>de</strong> solo lectura por lo que no actualizará en<br />

la base <strong>de</strong> datos.<br />

o No permitir nulos con NotAllowNulls(). Cuando un campo no tiene<br />

especificado ningún valor entonces por <strong>de</strong>fecto se graba un nulo, si por<br />

el contrario queremos que se guar<strong>de</strong> otro valor usaríamos este método.<br />

7


<strong>ControlsSAP</strong> Framework ®<br />

Public Class Contract<br />

Inherits <strong>ControlsSAP</strong>.SAPObject<br />

End Sub<br />

Public Sub New(ByVal Company As SAPbobsCOM.Company)<br />

MyBase.New(Company, "@GSP_CNTR")<br />

End Sub<br />

Protected Overri<strong>de</strong>s Function InitializeLines() As Long<br />

End Function<br />

Protected Overri<strong>de</strong>s Sub ModifyingObject()<br />

Listado 1: Ejemplo <strong>de</strong> creación <strong>de</strong> un objeto <strong>de</strong> negocio maestro.<br />

Después solamente <strong>de</strong>beremos crear una propiedad por cada campo <strong>de</strong> la tabla que vayamos a<br />

publicar. Para obtener o asignar el valor <strong>de</strong>l campo <strong>de</strong>l registro actual utilizaremos la función<br />

FilaActual(nombre_campo).<br />

Public ReadOnly Property Co<strong>de</strong>() As String<br />

Get<br />

Return Me.FilaActual("Co<strong>de</strong>")<br />

End Get<br />

End Property<br />

Public Property CardCo<strong>de</strong>() As String<br />

Get<br />

Return Me.FilaActual("U_GSP_CardCo<strong>de</strong>")<br />

End Get<br />

Set(ByVal value As String)<br />

Me.FilaActual("U_GSP_CardCo<strong>de</strong>") = Value<br />

End Set<br />

End Property<br />

Listado 2: Ejemplo <strong>de</strong> creación <strong>de</strong> propieda<strong>de</strong>s en objeto <strong>de</strong> negocio.<br />

Si no se especifica ningún valor para el campo Name (que crea en todas las tablas SAP) se le<br />

asignará el mismo valor que contenga el campo Co<strong>de</strong>, que por <strong>de</strong>fecto será el campo clave.<br />

2.3 Creación <strong>de</strong> los objetos <strong>de</strong>talle (SAPLines)<br />

Para crear un objeto <strong>de</strong>talle <strong>de</strong>beremos crear una nueva clase que here<strong>de</strong> <strong>de</strong><br />

<strong>ControlsSAP</strong>.SAPLines. Esta clase será muy parecida a la <strong>de</strong>l SAPObject pero con las<br />

particularida<strong>de</strong>s <strong>de</strong> trabajar con objetos <strong>de</strong> líneas parecidos a los <strong>de</strong> la DI <strong>de</strong> SAP.<br />

8


<strong>ControlsSAP</strong> Framework ®<br />

Object:<br />

<br />

Methods:<br />

+Add<br />

+SetCurrentLine<br />

+Delete<br />

Properties:<br />

Count<br />

…<br />

En esta clase también tendremos métodos para modificar la estructura <strong>de</strong> datos interna <strong>de</strong> la<br />

clase tal como se hace en el SAPObject. Y <strong>de</strong>beremos crear también una propiedad por cada<br />

campo <strong>de</strong> nuestra tabla.<br />

En el constructor <strong>de</strong>beremos indicar la tabla, el objeto cabecera y el campo que relaciona la<br />

tabla <strong>de</strong> líneas con la tabla cabecera.<br />

A diferencia <strong>de</strong> las líneas <strong>de</strong> la DI <strong>de</strong> SAP, en las SAPLines existe una diferencia a tener en<br />

cuenta:<br />

Siempre que se quiera añadir una nueva línea se <strong>de</strong>berá primero llamar al método Add() y<br />

<strong>de</strong>spués rellenar las propieda<strong>de</strong>s <strong>de</strong>l objeto. Por lo cual si no existe ninguna línea la propiedad<br />

Count() <strong>de</strong>volverá 0, a diferencia <strong>de</strong> las líneas <strong>de</strong>l SDK <strong>de</strong> SAP que <strong>de</strong>vuelven 1 aunque no<br />

exista ninguna entrada <strong>de</strong> datos.<br />

Public Class Contract_Lines<br />

Inherits <strong>ControlsSAP</strong>.SAPLines<br />

Friend Sub New(ByVal sapobject As Contract)<br />

MyBase.New("@GSP_CNT1", "U_GSP_CntrCo<strong>de</strong>", sapobject)<br />

End Sub<br />

Protected Overri<strong>de</strong>s Sub ModifyingLines()<br />

End Sub<br />

Public ReadOnly Property CntrCo<strong>de</strong>() As String<br />

Get<br />

Return Me.FilaActual("U_GSP_CntrCo<strong>de</strong>")<br />

End Get<br />

End Property<br />

Public Property ItemCo<strong>de</strong>() As String<br />

Aña<strong>de</strong> una nueva línea.<br />

Se posiciona en una línea <strong>de</strong>terminada.<br />

Elimina la línea actual.<br />

Devuelve el total <strong>de</strong> líneas.<br />

9


<strong>ControlsSAP</strong> Framework ®<br />

Get<br />

Return Me.FilaActual("U_GSP_ItemCo<strong>de</strong>")<br />

End Get<br />

Set(ByVal value As String)<br />

Me.FilaActual("U_GSP_ItemCo<strong>de</strong>") = value<br />

End Set<br />

End Property<br />

Public Property Import() As Double<br />

Get<br />

Return Me.FilaActual("U_GSP_Import")<br />

End Get<br />

Set(ByVal value As Double)<br />

Me.FilaActual("U_GSP_Import") = value<br />

End Set<br />

End Property<br />

Listado 3: Ejemplo creación <strong>de</strong> un objeto <strong>de</strong> tipo línea.<br />

Una vez tengamos la clase líneas creada <strong>de</strong>beremos crear una propiedad para tener acceso a<br />

estas en la clase maestra. Esta <strong>de</strong>berá ser <strong>de</strong> solo-lectura e instanciarse solamente si no tiene<br />

valor la variable que utilicemos para <strong>de</strong>finirla. No nos olvi<strong>de</strong>mos <strong>de</strong>spués <strong>de</strong> inicializar las líneas<br />

en el método InitializeLines.<br />

Private _lines As Contract_Lines<br />

Protected Overri<strong>de</strong>s Function InitializeLines() As Long<br />

Me.DestroyLines(_lines)<br />

End Function<br />

Public ReadOnly Property Cnt1() As Contract_Lines<br />

Get<br />

If Me._lines Is Nothing Then<br />

Me._lines = New Contract_Lines(Me)<br />

End If<br />

Return Me._lines<br />

End Get<br />

End Property<br />

Listado 4: Añadir referencia clase líneas en objeto cabecera.<br />

2.4 Utilización <strong>de</strong> un objeto <strong>de</strong> negocio<br />

Una vez <strong>de</strong>finidas todas las clases que componen nuestro objeto <strong>de</strong> negocio podremos ser<br />

capaces <strong>de</strong> utilizar este objeto para entrar datos, recuperar datos y actualizarlos.<br />

Dim cont As Contract<br />

cont = New Contract(Me.Company)<br />

10


<strong>ControlsSAP</strong> Framework ®<br />

cont.CardCo<strong>de</strong> = "C000001"<br />

cont.Comments = "Ejemplo creación <strong>de</strong> contrato"<br />

Try<br />

cont.Add()<br />

Catch ex As Exception<br />

<strong>ControlsSAP</strong>.SAPMsg.Alert("Error creando contrato")<br />

End Try<br />

Dim cont As Contract<br />

cont = New Contract(Me.Company)<br />

Listado 5: Ejemplo creación registro.<br />

'Consulta <strong>de</strong> un registro<br />

cont.GetByKey("1")<br />

cont.Comments = "Ejemplo actualización <strong>de</strong> contrato"<br />

Try<br />

cont.Update()<br />

Catch ex As Exception<br />

<strong>ControlsSAP</strong>.SAPMsg.Alert("Error actualizando contrato")<br />

End Try<br />

Listado 6: Ejemplo modificación <strong>de</strong> un registro existente.<br />

Este es un ejemplo <strong>de</strong> utilización por código, aunque lo común será tratar nuestros objetos <strong>de</strong><br />

negocio mediante formularios visuales. En el próximo capítulo veremos como existen<br />

formularios creados explícitamente para trabajar con este tipo <strong>de</strong> objetos y <strong>de</strong> una manera<br />

sencilla po<strong>de</strong>r crear, consultar, actualizar y eliminar registros.<br />

2.5 Tipo <strong>de</strong> validaciones <strong>de</strong>finidas<br />

Existirán 3 tipos <strong>de</strong> atributos que utilizaremos en las propieda<strong>de</strong>s <strong>de</strong> los clases SAPObject y<br />

SAPLines para realizar diferentes tipos <strong>de</strong> validaciones:<br />

• Mandatory: Forzaremos que en la propiedad se haya indicado un valor antes <strong>de</strong><br />

guardar. Si lo hacemos en una propiedad que <strong>de</strong>vuelve un SAPLines entonces exigirá<br />

que contenga al menos 1 línea.<br />

• HasRelation: Obliga a que el valor <strong>de</strong> la propiedad este relacionado con un<br />

<strong>de</strong>terminado campo <strong>de</strong> otra tabla.<br />

• NonUpdatable: No permite que se pueda modificar el valor <strong>de</strong> la propiedad una vez se<br />

ha creado el objeto.<br />

También existen 2 funciones por las que podremos saber si <strong>de</strong>s<strong>de</strong> nuestra clase cabecera<br />

SAPObject se han añadido líneas en una <strong>de</strong>terminada clase SAPLines o también si se han<br />

eliminado:<br />

• ExistAd<strong>de</strong>dLines<br />

11


<strong>ControlsSAP</strong> Framework ®<br />

• ExistDeletedLines.<br />

Ejemplo:<br />

Creamos un objeto Presupuesto e intentamos simular el mismo funcionamiento que un<br />

documento <strong>de</strong> la DI <strong>de</strong> SAP. Tendremos varios campos entre ellos el código <strong>de</strong> cliente y el<br />

nombre. Deberemos tener las siguientes restricciones:<br />

1. Para entrar una Presupuesto es obligatorio entrar el código <strong>de</strong> cliente.<br />

2. El código <strong>de</strong> cliente y el nombre no pue<strong>de</strong>n modificarse una vez creado el Presupuesto.<br />

3. El valor <strong>de</strong>l código <strong>de</strong> cliente <strong>de</strong>be existir en la tabla <strong>de</strong> clientes [OCRD.CardCo<strong>de</strong>]<br />

4. Una vez creado el Presupuesto no se permitirá añadir nuevas líneas ni eliminarlas.<br />

Public Class Presupuesto<br />

Inherits <strong>ControlsSAP</strong>.SAPObject<br />

'...<br />

_<br />

_<br />

_<br />

Public Property CardCo<strong>de</strong>() As String<br />

Get<br />

Return Me.FilaActual("U_GSP_CardCo<strong>de</strong>")<br />

End Get<br />

Set(ByVal Value As String)<br />

Me.FilaActual("U_GSP_CardCo<strong>de</strong>") = Value<br />

End Set<br />

End Property<br />

_<br />

Public Property CardName() As String<br />

Get<br />

Return Me.FilaActual("U_GSP_CardName")<br />

End Get<br />

Set(ByVal Value As String)<br />

Me.FilaActual("U_GSP_CardName") = Value<br />

End Set<br />

End Property<br />

Private Sub Oferta_Updating(ByVal Obj As SAPObject) Handles<br />

Me.Updating<br />

If Me.ExistAd<strong>de</strong>dLines(Me.Lines) Then<br />

Throw New ValidationException("No se pue<strong>de</strong> añadir<br />

una línea una vez creado el<br />

documento")<br />

End If<br />

If Me.ExistDeletedLines(Me.Lines) Then<br />

Throw New ValidationException("No se pue<strong>de</strong> borrar una<br />

fila una vez creado el<br />

documento ")<br />

12


<strong>ControlsSAP</strong> Framework ®<br />

End If<br />

End Sub<br />

Listado 7: Ejemplo <strong>de</strong> utilización <strong>de</strong> atributos <strong>de</strong> validación<br />

Este mismo tipo <strong>de</strong> restricciones las podríamos tener para el objeto líneas.<br />

2.6 Eventos<br />

Durante el momento <strong>de</strong> la ejecución <strong>de</strong> las diferentes acciones que soportan los objetos <strong>de</strong><br />

negoció, po<strong>de</strong>mos alterar los datos antes <strong>de</strong> que estos se guar<strong>de</strong>n o po<strong>de</strong>mos realizar<br />

validaciones propias para cancelar <strong>de</strong>terminadas acciones según nuestras necesida<strong>de</strong>s. El or<strong>de</strong>n<br />

secuencial <strong>de</strong> los diferentes eventos más comunes es:<br />

13


<strong>ControlsSAP</strong> Framework ®<br />

2.6.1 Altas/Modificaciones<br />

Add/Update<br />

Validaciones internas<br />

Validating<br />

Adding/Updating<br />

14<br />

Mandatory<br />

HasRelation<br />

NonUpdatable<br />

...<br />

Por cada línea <strong>de</strong>l SAPLines añadida/modificada:<br />

Recorre las líneas<br />

ValidatedLines<br />

Ad<strong>de</strong>d/Updated<br />

SavingLine<br />

ValidatingLine<br />

Base <strong>de</strong><br />

Datos


<strong>ControlsSAP</strong> Framework ®<br />

2.6.2 Eliminaciones<br />

Remove()<br />

Removing<br />

Eliminamos cada línea <strong>de</strong>l SAPLines:<br />

Recorre las líneas<br />

Removed<br />

15<br />

Delete()<br />

Base <strong>de</strong><br />

Datos


<strong>ControlsSAP</strong> Framework ®<br />

3 Diseño <strong>de</strong> pantallas<br />

visuales<br />

La librería <strong>de</strong> <strong>ControlsSAP</strong> incluye una serie <strong>de</strong> controles y formularios .NET pero con el<br />

Look&Feel <strong>de</strong> SAP, estos nos ayudaran a trabajar sin las limitaciones que tiene la UI ya que<br />

programaremos en la plataforma <strong>de</strong> Microsoft.NET 2.0.<br />

Por lo que aunque necesitemos algún tipo <strong>de</strong> control o funcionalidad que no este disponible en<br />

<strong>ControlsSAP</strong> podremos utilizarlo igualmente en nuestros proyectos con lo que po<strong>de</strong>mos utilizar<br />

una lista <strong>de</strong> recursos ilimitada, a diferencia <strong>de</strong> la programación con la UI.<br />

3.1 Controles<br />

En este apartado veremos una lista <strong>de</strong> controles disponibles en <strong>ControlsSAP</strong>. Estos controles<br />

dispondrán <strong>de</strong> una serie <strong>de</strong> propieda<strong>de</strong>s comunes, ya que la mayoría <strong>de</strong> ellos implementan una<br />

misma Interface.<br />

La mayoría <strong>de</strong> controles son típicos en Windows por lo que solamente se tratarán con mayor<br />

<strong>de</strong>talle los más importantes y complejos.<br />

La lista <strong>de</strong> controles disponibles con el Look&Feel <strong>de</strong> SAP:<br />

• SAPLabel: control <strong>de</strong> etiqueta.<br />

• SAPCheckBox: casilla <strong>de</strong> verificación.<br />

• SAPRadioButton: control <strong>de</strong> opciones.<br />

• SAPPanel: panel <strong>de</strong> agrupación <strong>de</strong> controles.<br />

• SAPTextBox: caja <strong>de</strong> texto.<br />

• SAPListBox: control <strong>de</strong> selección parecido al ChooseFromList <strong>de</strong> SAP.<br />

• SAPComboBox: control combo <strong>de</strong> selección.<br />

16


<strong>ControlsSAP</strong> Framework ®<br />

3.1.1 SAPTextBox<br />

• SAPLinkedButton: Control <strong>de</strong> vinculo o flecha naranja.<br />

• SAPGrid: control <strong>de</strong> grid.<br />

• SAPTree: control <strong>de</strong> árbol.<br />

• TreeSearch: control <strong>de</strong> búsquedas en una grid mediante una serie <strong>de</strong> filtros<br />

fijados.<br />

• SAPAttachments: control por el cual podremos anexar o visualizar diferentes<br />

archivos relacionados con un registro.<br />

Este es el control mas usado junto con las etiquetas SAPLabel. Son cajas <strong>de</strong> texto don<strong>de</strong> el<br />

usuario podrá introducir o consultar datos.<br />

Podremos <strong>de</strong>finir que tipo <strong>de</strong> datos va a utilizar el control y la entrada o salida variará según<br />

este.<br />

DataType SubDataType<br />

Numero<br />

Precio Aña<strong>de</strong> el símbolo <strong>de</strong> moneda y muestra los <strong>de</strong>cimales<br />

indicados en SAP para el tipo Precio.<br />

Importe Aña<strong>de</strong> el símbolo <strong>de</strong> moneda y muestra los <strong>de</strong>cimales<br />

indicados en SAP para el tipo Importe.<br />

Cantidad Muestra los <strong>de</strong>cimales indicados en SAP para el tipo<br />

Cantidad.<br />

Entero No muestra <strong>de</strong>cimales<br />

Porcentaje Muestra el símbolo <strong>de</strong> ‘%’<br />

Ca<strong>de</strong>na Para datos <strong>de</strong> tipo texto<br />

Memo Para datos <strong>de</strong> tipo texto con multilínea<br />

Fecha Fechas<br />

Hora Valores <strong>de</strong> tipo hora<br />

Los <strong>de</strong> tipo numérico solamente aceptarán entradas <strong>de</strong> datos numéricos. Si seleccionamos el<br />

tipo Fecha entonces se comportará como las entradas <strong>de</strong> fecha <strong>de</strong> SAP.<br />

3.1.2 SAPListBox<br />

Este control es también uno <strong>de</strong> los más utilizados en los formularios y <strong>de</strong> los más útiles ya que<br />

te permite seleccionar valores que pertenezcan a una lista <strong>de</strong> registros, <strong>de</strong> una manera sencilla<br />

y practica.<br />

17


<strong>ControlsSAP</strong> Framework ®<br />

Las propieda<strong>de</strong>s más utilizadas:<br />

• ValueMember: Indica <strong>de</strong> que columna obtendremos el valor una vez<br />

seleccionado un registro.<br />

• DisplayMember: Indica la columna será la que utilizaremos para mostrar en el<br />

control una vez seleccionado un valor.<br />

• SelectedValue: Propiedad en la que podremos asignar u obtener el valor <strong>de</strong>l<br />

registro seleccionado y que hemos indicado el la propiedad ValueMember.<br />

Otros <strong>de</strong> los métodos más comunes:<br />

• AddColumn: Añadiremos las columnas que queremos visualizar en la lista <strong>de</strong><br />

registros.<br />

• SetItemValue: Des<strong>de</strong> este método po<strong>de</strong>mos asignar también un valor al control<br />

pero sin provocar el evento SelectedValueChaged, a diferencia <strong>de</strong> hacerlo con<br />

SelectedValue.<br />

La lista <strong>de</strong> datos que mostrará el control pue<strong>de</strong> venir <strong>de</strong> diferentes orígenes:<br />

• Indicando la tabla <strong>de</strong> la que se obtendrán los datos<br />

With Me.SapListBox1<br />

.Table = "OCRD"<br />

.ValueMember = "CardCo<strong>de</strong>"<br />

.DisplayMember = "CardName"<br />

.Condition = "CardType='C'"<br />

.Company = Me._company<br />

End With<br />

• Asignándole un objeto DataTable a su propiedad DataSource:<br />

18


<strong>ControlsSAP</strong> Framework ®<br />

Dim dt as DataTable<br />

dt = <strong>ControlsSAP</strong>.DoQuery(“SELECT * FROM OCRD”)<br />

Me.SapListBox1.DataSource = dt<br />

• Añadiendo los valores manualmente con el método InsertRow<br />

With Me.SapListBox1<br />

.InsertRow("O", "Abierto")<br />

.InsertRow("C", "Cerrado")<br />

.InsertRow("P", "Pendiente")<br />

End With<br />

• También podremos añadir valores con:<br />

o AddValidValues: Consulta la lista <strong>de</strong> valores validos <strong>de</strong>finidos para un<br />

campo <strong>de</strong> SAP.<br />

o AssignEnum: muestra la lista <strong>de</strong> valores <strong>de</strong> la enumeración indicada.<br />

Cuando asignemos los datos mediante la propiedad Table y queramos añadir un registro propio<br />

cada vez que se carguen los datos, utilizaremos el evento SAPListBox.BoundTable.<br />

Private Sub lstIC_BoundTable(...) Handles SapListBox1.BoundTable<br />

Me.lstIC.InsertRow("-1", "-Ningún Interlocutor comercial-", 0)<br />

End Sub<br />

Listado 8: Después <strong>de</strong> cada carga <strong>de</strong> IC, añadimos un nuevo valor.<br />

También po<strong>de</strong>mos utilizar la propiedad DisplayControl para especificar otro control en el que<br />

se volcarán los datos correspondientes a la columna especificada en el DisplayMember. En vez<br />

<strong>de</strong> mostrarse la <strong>de</strong>scripción en el mismo control se mostrará en el control que indiquemos.<br />

3.1.3 SAPComboBox<br />

El control SAPComboBox incorpora la mayoría <strong>de</strong> funciones y propieda<strong>de</strong>s <strong>de</strong>l control<br />

SAPListBox anterior pero con el aspecto <strong>de</strong> un control combo. Este se utiliza normalmente para<br />

mostrar listas pequeñas <strong>de</strong> valores.<br />

19


<strong>ControlsSAP</strong> Framework ®<br />

Para los controles <strong>de</strong> lista se ha añadido nueva funcionalidad para po<strong>de</strong>r añadir registros<br />

nuevos <strong>de</strong>s<strong>de</strong> el mismo control, ahorrándonos el trabajo <strong>de</strong> tener que ir a buscar la opción <strong>de</strong><br />

menú correspondiente a esta acción.<br />

Podremos añadir registros indicando:<br />

• El nombre <strong>de</strong> la tabla: que abrirá un formulario <strong>de</strong> alta <strong>de</strong> registros típico<br />

(FormSAPAlta)<br />

• El tipo <strong>de</strong> formulario: abrirá el formulario <strong>de</strong> mantenimiento en modo crear. Este tiene<br />

que heredar <strong>de</strong> FormEditSAP.<br />

• El id. <strong>de</strong> menú <strong>de</strong> SAP: con este i<strong>de</strong>ntificador (MenuUID) abriremos la pantalla<br />

correspondiente en SAP. Para este tipo <strong>de</strong> formularios no se podrán añadir los registros<br />

creados en el control, solamente servirá para abrir el formulario <strong>de</strong> SAP.<br />

Las funciones que utilizaremos para el SAPListBox son:<br />

• SetFormToCreate: Que añadirá el botón <strong>de</strong> “Nuevo” en el formulario <strong>de</strong> selección.<br />

Y para el control SAPComboBox:<br />

• InsertCreateRow: Que creará un nuevo registro “Definir nuevo”.<br />

20


<strong>ControlsSAP</strong> Framework ®<br />

3.1.4 SAPGrid<br />

Complejo control <strong>de</strong> Grid que nos servirá para mostrar un conjunto <strong>de</strong> valores y para realizar el<br />

mantenimiento <strong>de</strong> los objetos SAPLines.<br />

Podremos añadir diferentes tipos <strong>de</strong> columnas según el tipo <strong>de</strong> datos que queramos mostrar:<br />

• AddColumn: Aña<strong>de</strong> una columna genérica según el tipo <strong>de</strong> datos que vaya a<br />

mostrar.<br />

• AddPriceColumn: columna para datos <strong>de</strong> tipo precio. Visualizará el símbolo <strong>de</strong><br />

moneda y los <strong>de</strong>cimales <strong>de</strong>finidos en SAP para el tipo Precio.<br />

• AddImportColumn: columna para datos <strong>de</strong> tipo importe. Visualizará el símbolo<br />

<strong>de</strong> moneda y los <strong>de</strong>cimales <strong>de</strong>finidos en SAP para el tipo Importe.<br />

• AddQuantityColumn: columna para datos <strong>de</strong> tipo cantidad. Visualizará los<br />

<strong>de</strong>cimales <strong>de</strong>finidos en SAP para el tipo Cantidad.<br />

• AddPercentatgeColumn: visualiza el símbolo <strong>de</strong> ‘%’<br />

21


<strong>ControlsSAP</strong> Framework ®<br />

• AddBooleanSAPColumn: visualizara una columna con formato checkbox para<br />

datos alfanuméricos con valores Y o N (Yes/No)<br />

• AddListColumn: parecido al control SAPListBox, don<strong>de</strong> le indicaremos un<br />

origen <strong>de</strong> datos y la celda <strong>de</strong> la grid solamente podrá se un valor <strong>de</strong> esta lista.<br />

• AddComboBoxColumn: visualizara una celda <strong>de</strong> tipo combo para la selección<br />

<strong>de</strong> un valor en una lista indicada <strong>de</strong> valores.<br />

• AddProgressBarColumn: muestra una barra <strong>de</strong> progreso según el valor actual<br />

<strong>de</strong> la celda.<br />

AddMemoColumn: podremos añadir columnas con textos lagos en varias líneas.<br />

AddImageColumn: añadiremos columnas para mostrar imágenes <strong>de</strong>s<strong>de</strong> una ruta. Deberemos<br />

indicar un campo que será el que contenga la ruta específica <strong>de</strong> la imagen.<br />

Otras configuraciones que pue<strong>de</strong> tener la grid:<br />

• ObjectSource: propiedad para asignar los datos <strong>de</strong> un objeto SAPLines como<br />

origen <strong>de</strong> datos.<br />

• AcceptsAddLines: nos indica si se pue<strong>de</strong>n añadir nuevas líneas en la grid.<br />

• AcceptsDeleteLines: indica si podremos eliminar registros <strong>de</strong> la grid.<br />

• Editable: Indica si la grid permitirá edición <strong>de</strong> sus celdas<br />

• ShowEmptyLine: muestra una fila vacía para la entrada <strong>de</strong> nuevos registros.<br />

• MarkRow: Marca las filas en negrita que cumplan un criterio establecido.<br />

• DisableRows: Deshabilita las filas que cumplan con un criterio.<br />

• SelectRow: selecciona una o varias filas<br />

• GetSAPLine: posiciona el objeto SAPLines según la fila indicada <strong>de</strong> la grid.<br />

En próximos apartados veremos como trabajar un objeto <strong>de</strong> negocio <strong>de</strong>s<strong>de</strong> un formulario. Los<br />

objetos líneas se trabajarán con el control SAPGrid que dispone <strong>de</strong> varios eventos especiales<br />

que nos informarán <strong>de</strong> cualquier modificación en las líneas:<br />

• UpdatingSAPLine<br />

• UpdateSAPLine<br />

• ValidateSAPLine<br />

• DeletedSAPLine<br />

• DeletingSAPLine<br />

3.1.4.1 Multiselección<br />

Las columnas <strong>de</strong> tipo lista (AddListColumn) disponen <strong>de</strong> la opción <strong>de</strong> multiselección. Existe un<br />

parámetro por el que podremos indicar si queremos utilizar multi-selección o no. Los eventos<br />

22


<strong>ControlsSAP</strong> Framework ®<br />

UpdateSAPLine/ UpdatingSAPLine <strong>de</strong>l SAPGrid se ejecutarán por cada fila, como si las<br />

hubieramos entrado una a una.<br />

Si alguna <strong>de</strong> las filas no pasa con éxito la validación entonces no se añadirá en la grid.<br />

c = .AddListColumn("Cód.artículo", "U_GSP_ItemCo<strong>de</strong>", Me._company,<br />

"OITM", "ItemCo<strong>de</strong>", New String() {"ItemName", "ItemCo<strong>de</strong>", _<br />

"VatGourpSa", "ItmsGrpCod"}, , ,<br />

True)<br />

3.1.4.2 Columnas obligatorias<br />

Existe un método en el control SAPGrid por el que podremos indicar si alguna <strong>de</strong> las columnas<br />

que hemos añadido es una columna <strong>de</strong> inicio, que quiere <strong>de</strong>cir que es obligatorio que<br />

introduzcamos un valor en una <strong>de</strong> estas columnas antes que en ninguna otra.<br />

Ejemplo:<br />

No podremos introducir ningún valor en las líneas mientras no exista un valor en la columna <strong>de</strong><br />

artículo:<br />

.AddBeginningColumn("U_GSP_ItemCo<strong>de</strong>")<br />

Listado 9: Código <strong>de</strong> ejemplo para indicar un columna obligatoria.<br />

23


<strong>ControlsSAP</strong> Framework ®<br />

Figura 1: Ejemplo <strong>de</strong> advertencia al intentar introducir un valor en una columna diferente a la indicada<br />

como obligatoria.<br />

Se ha publicado también un evento ShowingEditor por el que podremos conseguir efectos<br />

parecidos al anterior, o sea no permitir la edición <strong>de</strong> una celda mientras no se cumplan<br />

<strong>de</strong>terminados criterios.<br />

Ejemplo:<br />

No po<strong>de</strong>mos introducir ningún valor en la grid mientras no se haya introducido el código <strong>de</strong>l<br />

cliente (campo <strong>de</strong> cabecera):<br />

Private Sub SapGrid1_ShowingEditor(...) Handles SapGrid1.ShowingEditor<br />

If Not Me.lstCardCo<strong>de</strong>.HasValue Then<br />

<strong>ControlsSAP</strong>.SAPMsg.StatusBarMsg("Falta código <strong>de</strong><br />

interlocutor comercial", True)<br />

e.Cancel = True<br />

End If<br />

End Sub<br />

3.1.5 SAPTreeSearch<br />

Control <strong>de</strong> vista <strong>de</strong> datos para realizar diferentes tipos <strong>de</strong> filtros (panel izquierda). A<strong>de</strong>más <strong>de</strong><br />

po<strong>de</strong>r filtrar en tiempo <strong>de</strong> ejecución.<br />

24


<strong>ControlsSAP</strong> Framework ®<br />

3.1.6 SAPAttachments<br />

Control utilizaremos para adjuntar o visualizar archivos en una carpeta <strong>de</strong> documentos anexos<br />

<strong>de</strong> una manera sencilla.<br />

Podremos realizar las siguientes acciones:<br />

Explorar: Seleccionaremos un archivo y lo anexaremos por <strong>de</strong>fecto en la carpeta <strong>de</strong> documentos<br />

<strong>de</strong> anexo especificada en SAP. Si indicamos una ruta mediante la propiedad AttachmentPath<br />

entonces se utilizará esta ruta para realizar una copia <strong>de</strong>l archivo.<br />

Visualizar: Abrirá el documento seleccionado.<br />

Borrar: Eliminará el documento seleccionado <strong>de</strong> la lista <strong>de</strong> documentos <strong>de</strong>l control.<br />

Drag&Drop: El control permite la posibilidad <strong>de</strong> arrastrar y soltar archivos <strong>de</strong>ntro <strong>de</strong> este, con lo<br />

que se creara una copia <strong>de</strong>l archivo en la ruta <strong>de</strong> anexos especificada.<br />

También permitirá arrastrar y soltar mensajes <strong>de</strong> correo <strong>de</strong>s<strong>de</strong> Microsoft Outlook.<br />

25


<strong>ControlsSAP</strong> Framework ®<br />

Se utilizará para guardar documentos adjuntos por ejemplo en un SAPObject. Para ello<br />

solamente necesitaremos una propiedad <strong>de</strong> tipo String don<strong>de</strong> guardaremos la lista <strong>de</strong><br />

archivos en ca<strong>de</strong>na y separados por punto y coma.<br />

Para obtener la lista <strong>de</strong> archivos utilizaremos la propiedad Attachments <strong>de</strong>l control.<br />

3.2 Pantallas<br />

Existen varios tipos <strong>de</strong> pantallas con las que podremos trabajar. La base <strong>de</strong> todas ellas será la<br />

clase <strong>ControlsSAP</strong>.Forms.FormSAP. Esta clase será la que utilicemos normalmente y la que<br />

proporcionará a nuestros formularios el aspecto <strong>de</strong> pantalla <strong>de</strong> SAP e incluirán todos los<br />

mecanismos <strong>de</strong> integración en SAP Business One como si fueran pantallas propias <strong>de</strong> la UI.<br />

3.2.1 FormSAP<br />

Este tipo <strong>de</strong> formulario será la clase base <strong>de</strong> las que heredarán todos nuestros formularios. Con<br />

esto dispondremos <strong>de</strong> todos los métodos, funciones y propieda<strong>de</strong>s que nos servirán para<br />

interactuar con las <strong>de</strong>más pantallas y facilitarán la integración con SAP.<br />

Podremos interactuar con algunos botones <strong>de</strong> la barra <strong>de</strong> herramientas <strong>de</strong> SAP Business One<br />

como son los <strong>de</strong> Excel, los <strong>de</strong> Word, los <strong>de</strong> impresión y presentación preliminar, y también los<br />

<strong>de</strong> mailing. Para ello disponemos <strong>de</strong> una serie <strong>de</strong> eventos y <strong>de</strong> propieda<strong>de</strong>s para habilitar o no<br />

los botones <strong>de</strong> la barra <strong>de</strong> herramientas:<br />

• AcceptsExcel: Habilita el botón <strong>de</strong> Excel <strong>de</strong> la barra <strong>de</strong> herramientas y po<strong>de</strong>mos<br />

capturar la pulsación a través <strong>de</strong>l evento Excel.<br />

• Word Habilita el botón <strong>de</strong> Word <strong>de</strong> la barra <strong>de</strong> herramientas y po<strong>de</strong>mos<br />

capturar la pulsación a través <strong>de</strong>l evento Word.<br />

• AcceptsPrint/AcceptsPreview: Habilita la impresión/presentación preliminar<br />

que capturaremos <strong>de</strong>s<strong>de</strong> el evento Print<br />

• eMailing: será el evento que capturaremos si queremos modificar la pantalla <strong>de</strong><br />

mailing que aparecerá por <strong>de</strong>fecto. Como por ejemplo añadir un <strong>de</strong>stinatario,<br />

datos adjuntos, etc.<br />

También tendremos funciones muy utilizadas como:<br />

• OpenForm: Abre un formulario y lo integra en SAP automáticamente.<br />

• OpenFormDialog: abre un formulario en modo dialogo para obtener un<br />

resultado.<br />

• OpenFormEdit: abre un formulario <strong>de</strong> edición (que veremos en el próximo<br />

apartado) y se sitúa en un registro indicado.<br />

• OpenReport: muestra una pre-visualización <strong>de</strong> un informe <strong>de</strong> CrystalReports.<br />

26


<strong>ControlsSAP</strong> Framework ®<br />

3.2.2 FormEditSAP<br />

Nos permite realizar el mantenimiento <strong>de</strong> los objetos <strong>de</strong> negocio creados a partir <strong>de</strong> un<br />

SAPObject <strong>de</strong> una manera rápida y sencilla. Este es formulario mas complejo que existe pero<br />

también el mas utilizado, por lo que <strong>de</strong>dicaremos un capitulo especifico para hablar <strong>de</strong> el.<br />

Este tipo <strong>de</strong> formularios interactúa con los botones <strong>de</strong> la barra <strong>de</strong> herramientas referentes al<br />

mantenimiento <strong>de</strong> datos, a <strong>de</strong>más <strong>de</strong> los ya mencionados anteriormente por el hecho <strong>de</strong><br />

heredar <strong>de</strong> FormSAP. Estos son:<br />

• AcceptsAdd: permite tener habilitado el botón <strong>de</strong> Nuevo.<br />

• AcceptsDelete: habilita la opción <strong>de</strong> menú <strong>de</strong> eliminar.<br />

• AcceptsSearch: activa el botón <strong>de</strong> búsquedas<br />

• AcceptsUpdate: habilita los botones <strong>de</strong> <strong>de</strong>splazamiento <strong>de</strong> registros (primero,<br />

anterior, siguiente, ultimo)<br />

Una vez configuradas las acciones que queremos tener disponibles en nuestra pantalla<br />

<strong>de</strong>beremos conocer los estados que pue<strong>de</strong> tener el formulario por motivo <strong>de</strong> realizar<br />

cualquiera <strong>de</strong> estas acciones. Des<strong>de</strong> la propiedad Estat podremos saber si estamos en alguno <strong>de</strong><br />

los estados siguientes:<br />

• CONSULTING: indica que estamos en un estado <strong>de</strong> consulta. Se provoca en el<br />

momento <strong>de</strong> <strong>de</strong>splazarse entre los registros<br />

• UPDATE: indica que estamos realizando una actualización en un registro ya<br />

existente. La mayoría <strong>de</strong> los controles vistos hasta ahora disponen <strong>de</strong> una<br />

propiedad CausesActionUpdate que si esta activada indicará que cualquier<br />

cambio en ese control provocará un cambio <strong>de</strong> estado en el formulario.<br />

• SEARCH: no se utiliza.<br />

• ADD/ADDING: nos informa <strong>de</strong> que se esta añadiendo un nuevo registro.<br />

Existe una propiedad ButtonForm para indicar que botón <strong>de</strong>l formulario será el indicado en<br />

recibir los cambios <strong>de</strong> estado <strong>de</strong>l formulario y proce<strong>de</strong>r a un tipo <strong>de</strong> acción u otra <strong>de</strong>pendiendo<br />

<strong>de</strong> este:<br />

Estado Texto <strong>de</strong>l ButtonForm Acción<br />

CONSULTING “Ok” Cerrar el formulario<br />

UPDATE “Actualizar” Actualizar los datos<br />

ADD “Crear” Crea un nuevo registro<br />

Todo este tipo <strong>de</strong> acciones tienen una serie <strong>de</strong> métodos asignados que podremos sobrescribir<br />

para añadir funcionalidad propia según nuestras necesida<strong>de</strong>s:<br />

• DoAdd: prepara el formulario para crear un nuevo registro. Se ejecuta en el<br />

momento <strong>de</strong> <strong>de</strong> pulsar sobre el botón <strong>de</strong> “Nuevo”. Po<strong>de</strong>mos utilizarlo para<br />

asignar valores por <strong>de</strong>fecto en los controles.<br />

27


<strong>ControlsSAP</strong> Framework ®<br />

• DoDelete: realiza la acción <strong>de</strong> eliminar el registro actual. Se ejecuta cuando<br />

pulsamos sobre la opción <strong>de</strong> menú Datos Eliminar<br />

• DoSearch: realiza una búsqueda entre todos los datos. Se obtiene cuando<br />

pulsamos sobre buscar.<br />

• GoToFirst: se <strong>de</strong>splaza al primer registro.<br />

• GoToLast: nos <strong>de</strong>splazamos al último registro.<br />

• GoToPrevious: nos <strong>de</strong>splazamos al registro anterior.<br />

• GoToNext: registro siguiente<br />

• GoToKey: <strong>de</strong> posiciona en el registro que coincida con la clave indicada.<br />

3.2.2.1 Carga <strong>de</strong> datos<br />

Existirán 2 maneras <strong>de</strong> cargar datos en un FormEditSAP trabajando con un objeto <strong>de</strong> negocio<br />

SAPObject.<br />

• Usando GetAllObjects:<br />

Esta es la manera más usual <strong>de</strong> obtener los datos en un FormEditSAP.<br />

Podremos consultar todos los datos <strong>de</strong>l objeto existentes en ese momento. Se<br />

pue<strong>de</strong> también indicar por que campo queremos que aparezcan or<strong>de</strong>nados los<br />

registros.<br />

28


<strong>ControlsSAP</strong> Framework ®<br />

Deberemos asignar el objeto al formulario y este se encargará <strong>de</strong> consultar los<br />

datos <strong>de</strong>l registro indicado en cada momento.<br />

_of = New Oferta(_company)<br />

Me.GetAllObjects(_of, "U_GSP_CardName")<br />

Listado 10: Instanciación y uso <strong>de</strong>l un SAPObject en un FormEditSAP.<br />

• Usando el GetSAPObject <strong>de</strong>l objeto:<br />

Otra manera <strong>de</strong> consultar los datos <strong>de</strong> un objeto es la <strong>de</strong> asignarle previamente<br />

el origen <strong>de</strong> datos (por el que queremos navegar) al Browser <strong>de</strong>l objeto. Es<br />

necesario que en el origen <strong>de</strong> datos exista un campo con la clave principal <strong>de</strong>l<br />

objeto.<br />

Para ello utilizaremos el método GetSAPObject que indicará al formulario que<br />

<strong>de</strong>be trabajar con los datos <strong>de</strong>l objeto actual.<br />

Ejemplo: Solamente podremos navegar por registros don<strong>de</strong> el total sea mayor<br />

<strong>de</strong> 1000.<br />

29<br />

Browser<br />

Base <strong>de</strong><br />

datos


<strong>ControlsSAP</strong> Framework ®<br />

Dim dt As DataTable<br />

dt =DoQuery("SELECT Co<strong>de</strong>, U_CardCo<strong>de</strong>, U_CardName, U_DocDate<br />

FROM [@GSP_DEMO_OFERTA]<br />

WHERE (U_GSP_DocTotal > '1000')", Me._company)<br />

If dt.Rows.Count > 0 Then<br />

_of.Browser.RecordSet = dt<br />

End If<br />

Me.GetSAPObject(_of)<br />

Listado 11: Utilización <strong>de</strong>l Browser y uso <strong>de</strong>l GetSAPObejct.<br />

Solo podremos <strong>de</strong>splazarnos por los registros seleccionados en el momento <strong>de</strong> cargar el<br />

Browser <strong>de</strong>l objeto. Por los que si existen nuevos registros creados posteriormente por otros<br />

usuario o procesos no se visualizarán, pero si los cambios ya que en cada movimiento se<br />

refrescarán los datos <strong>de</strong>l objeto actual.<br />

Por <strong>de</strong>fecto si no se especifica ninguna acción en el momento <strong>de</strong> la carga el formulario se<br />

posicionará en el último registro.<br />

3.2.3 FormWizard<br />

Este tipo <strong>de</strong> formulario pue<strong>de</strong> ser muy útil para realizar pantallas asistentes <strong>de</strong> forma rápida y<br />

práctica. Consistirá en un formulario con un control <strong>de</strong> pestañas que en el momento <strong>de</strong><br />

ejecución se visualizará como una pantalla asistente propia <strong>de</strong> las <strong>de</strong> SAP.<br />

Permitiremos realizar un cambio <strong>de</strong> página <strong>de</strong>pendiendo <strong>de</strong> si se cumplen las validaciones que<br />

creemos oportunas, capturando los eventos:<br />

• PageChanged<br />

• PageChanging<br />

30


<strong>ControlsSAP</strong> Framework ®<br />

Estos eventos nos informarán <strong>de</strong> que página venimos y a que página nos dirigimos. Podremos<br />

cambiar la información <strong>de</strong>scriptiva <strong>de</strong> la página actual por medio <strong>de</strong> la propiedad Description.<br />

También podremos <strong>de</strong>splazarnos por las páginas a través <strong>de</strong> código mediante:<br />

• NextPage: nos <strong>de</strong>splazamos a la página siguiente.<br />

• PreviousPage: nos movemos a la anterior página.<br />

• ActualPage. Po<strong>de</strong>mos obtener en que pagina estamos actualmente y po<strong>de</strong>mos<br />

<strong>de</strong>splazarnos también a una página en concreto asignándole un valor.<br />

El formulario asistente podrá tener 2 configuraciones diferentes según la propiedad PageEnd:<br />

3.2.4 FormSAPAlta<br />

1. Si es “False” al llegar a la última página el botón <strong>de</strong> continuar quedará<br />

<strong>de</strong>shabilitado.<br />

2. Si es “True” en la última página aparecerá un botón <strong>de</strong> finalizar que lanzará un<br />

evento FinalizeWizard que <strong>de</strong>beremos capturar para ejecutar las acciones<br />

necesarias al finalizar el asistente.<br />

Es un sencillo y práctico tipo <strong>de</strong> formulario que utilizaremos para crear o actualizar registros en<br />

una tabla <strong>de</strong> usuario <strong>de</strong> SAP. Estas pantallas son útiles para tablas básicas, don<strong>de</strong> solamente sea<br />

necesario indicar un código y una <strong>de</strong>scripción.<br />

Podremos utilizarlas sobre todo para realizar mantenimientos <strong>de</strong> tablas en entornos fuera <strong>de</strong><br />

SAP Business One.<br />

Figura 2: Ejemplo <strong>de</strong> pantalla tipo FormSAPAlta.<br />

31


<strong>ControlsSAP</strong> Framework ®<br />

3.2.5 FormApplication<br />

Si queremos reutilizar nuestro código en un entorno fuera <strong>de</strong> SAP Business One, podremos<br />

simular un entorno parecido en aspecto y funcionalida<strong>de</strong>s vistas, utilizando el tipo <strong>de</strong><br />

formulario FormApplication. Con el dispondremos <strong>de</strong> una interficie parecida a la <strong>de</strong> SAP<br />

incluyendo la barra <strong>de</strong> herramientas, barra <strong>de</strong> menú, menú principal, etc. Dispone <strong>de</strong> métodos<br />

para:<br />

• Conectar a la base <strong>de</strong> datos<br />

• Añadir los módulos <strong>de</strong> trabajo y sus menús<br />

• Abrir formularios<br />

• Desplazarse por los registros, crear, buscar, etc.…<br />

• Gestionar las aplicaciones<br />

• Control <strong>de</strong> versiones<br />

En el evento Load <strong>de</strong>l formulario llamaremos a la función Connect. Esta función realizará la<br />

conexión a la última base <strong>de</strong> datos <strong>de</strong> SAP conectada. Si es la primera vez se mostrará un<br />

formulario en el que indicaremos los datos necesarios para la conexión.<br />

Para cargar módulos <strong>de</strong> trabajo utilizaremos AddNewModule/AddItemModule y lo<br />

realizaremos en el evento LoadModules. Si estos necesitan crear tablas, campos, etc. lo<br />

realizarán antes <strong>de</strong> iniciarse la aplicación informando al usuario <strong>de</strong> los cambios que se van a<br />

realizar para cada módulo.<br />

Public Class frmMenu<br />

Private Sub frmMenu_Load(ByVal sen<strong>de</strong>r As Object, ByVal e As<br />

EventArgs) Handles MyBase.Load<br />

Me.Connect()<br />

End Sub<br />

Private Sub frmMenu_LoadModules(ByVal sen<strong>de</strong>r As Object, ByVal e As<br />

EventArgs) Handles Me.LoadModules<br />

Me.AddItemsModule(DLL.LoadDLL(Me.Company))<br />

End Sub<br />

End Class<br />

Listado 12: Conexión y arranque <strong>de</strong> un módulo <strong>de</strong>s<strong>de</strong> un formulario FormApplication.<br />

32


<strong>ControlsSAP</strong> Framework ®<br />

Figura 3: Ejemplo FormApplicacion.<br />

33


<strong>ControlsSAP</strong> Framework ®<br />

4 Formulario <strong>de</strong> edición<br />

(FormEditSAP)<br />

En este capitulo veremos en profundidad como trabajar un objeto <strong>de</strong> negocio SAPObject a<br />

través <strong>de</strong> un formulario <strong>de</strong> edición FormEditSAP.<br />

4.1 Diseño <strong>de</strong>l formulario<br />

Primero <strong>de</strong> todo diseñaremos una pantalla que here<strong>de</strong> <strong>de</strong> FormEditSAP y le añadiremos los<br />

controles necesarios para po<strong>de</strong>r editar el objeto con el que vayamos a trabajar.<br />

Figura 4: Ejemplo diseño <strong>de</strong> un formulario <strong>de</strong> edición.<br />

34


<strong>ControlsSAP</strong> Framework ®<br />

El objeto <strong>de</strong> negocio con el que trabajaremos será el visto en ejemplos anteriores. Para el<br />

mantenimiento <strong>de</strong> las propieda<strong>de</strong>s <strong>de</strong>l objeto Contrato necesitaremos añadir los siguientes<br />

controles y configurarlos <strong>de</strong> manera:<br />

1. “Código”: SAPTextBox, no acepta ediciones ni en alta ni en actualizaciones.<br />

2. “Código cliente”: SAPListBox, <strong>de</strong> consulta <strong>de</strong> los clientes<br />

• Table = “OITM”<br />

• ValueMember =”CardCo<strong>de</strong>”<br />

• DisplayMember = “CardName”<br />

• Condition = “CardType=’C’”<br />

3. “Fecha Inicio”/”Fecha Fin”: SAPTextBox acepta todo tipo <strong>de</strong> ediciones<br />

• DataType = Fecha<br />

4. “Comentarios”: SAPTextBox multilínea, acepta todo tipo <strong>de</strong> ediciones<br />

• DataType = Memo<br />

5. “Líneas <strong>de</strong> contrato”: Las líneas las trabajaremos mediante un SAPGrid.<br />

A todos estos controles les <strong>de</strong>beremos indicar también las propieda<strong>de</strong>s siguientes para que<br />

interactúen con el estado <strong>de</strong>l formulario:<br />

• CausesActioUpdate = True<br />

• CausesAspectChage = True<br />

4.2 Configurar el formulario<br />

El paso siguiente será entrar ya en el código y crear un constructor que reciba un objeto<br />

SAPBobsCOM.Company. Definiremos dos variables <strong>de</strong> clase que utilizaremos para el objeto <strong>de</strong><br />

negocio con el que trabajará el formulario y la otra variable para referenciar la Company.<br />

End Sub<br />

Private _company As SAPbobsCOM.Company<br />

Private _obj As Contract<br />

Public Sub New(ByVal Company As SAPbobsCOM.Company)<br />

MyBase.New()<br />

'El Diseñador <strong>de</strong> Windows Forms requiere esta llamada.<br />

InitializeComponent()<br />

'Agregar cualquier inicialización <strong>de</strong>spués <strong>de</strong> la llamada a<br />

'InitializeComponent()<br />

Me._company = Company<br />

Listado 13: Ejemplo constructor <strong>de</strong> un FormEditSAP.<br />

35


<strong>ControlsSAP</strong> Framework ®<br />

Una vez <strong>de</strong>finido el constructor pasaremos a configurar los controles que utilizará el formulario.<br />

Para ello utilizaremos el evento Load <strong>de</strong>l formualrio. Definiremos también con el método<br />

ViewColumnInSearch las columnas que queremos que se muestren en el momento <strong>de</strong> las<br />

búsquedas.<br />

Private Sub FormEditSAP1_Load(ByVal sen<strong>de</strong>r As Object, _<br />

ByVal e As EventArgs) Handles MyBase.Load<br />

'Configuración <strong>de</strong> la busqueda <strong>de</strong>l formulario<br />

Me.ViewColumnInSearch("Co<strong>de</strong>", "Código")<br />

Me.ViewColumnInSearch("U_GSP_CardCo<strong>de</strong>", "Código cliente")<br />

Me.ViewColumnInSearch("U_GSP_DataIn", "Fecha inicio")<br />

Me.ViewColumnInSearch("U_GSP_DateOut", "Fecha <strong>de</strong> fin")<br />

'Configuración <strong>de</strong>l Listbox <strong>de</strong> clientes<br />

With lstCardCo<strong>de</strong><br />

.Company = Me._company<br />

.AddColumn("CardCo<strong>de</strong>", "Código")<br />

.AddColumn("CardName", "Nombre", 200)<br />

.AddColumn("Phone1", "Teléfono")<br />

End With<br />

'Configuración <strong>de</strong> la Grid<br />

With grdCnt1<br />

.AddListColumn("Cod. Artículo", "U_GSP_ItemCo<strong>de</strong>", _<br />

Me._company, "OITM", "ItemCo<strong>de</strong>", _<br />

New String() {"ItemName"})<br />

.AddColumn("Descripción", "ItemName")<br />

.AddQuantityColumn("Cantidad inicial", "U_GSP_QuantIn")<br />

.AddQuantityColumn("Cantidad final", "U_GSP_QuantOut")<br />

.AddImportColumn("Importe", "U_GSP_Import")<br />

End With<br />

Listado 14: Ejemplo configuración <strong>de</strong>l formulario y sus controles.<br />

Existe la posibilidad también, en el momento <strong>de</strong> buscar , <strong>de</strong> hacer aparecer datos <strong>de</strong> otras<br />

tablas sobrescribiendo la consulta <strong>de</strong>l formulario.<br />

Para ello <strong>de</strong>beremos capturar el evento BuldingSearch. Como requisito indispensable <strong>de</strong>be<br />

aparecer como mínimo el campo clave <strong>de</strong>l objeto en la nueva búsqueda.<br />

Private Sub frmOferta_BuldingSearch(ByRef sqlQuery As String) Handles _<br />

Me.BuldingSearch<br />

sqlQuery = "SELECT [@GSP_DEMO_OFERTA].Co<strong>de</strong>, OCRD.CardCo<strong>de</strong>,<br />

OCRD.CardName, OCRD.Address<br />

FROM [@GSP_DEMO_OFERTA] INNER JOIN OCRD<br />

ON [@GSP_DEMO_OFERTA].U_GSP_CardCo<strong>de</strong> =<br />

OCRD.CardCo<strong>de</strong>"<br />

End Sub<br />

Listado 15: Ejemplo utilización búsqueda propia con BuldingSearch.<br />

También instanciaremos el objeto y cargaremos todos los datos por <strong>de</strong>fecto <strong>de</strong>l objeto <strong>de</strong><br />

negocio para po<strong>de</strong>r empezar a trabajar con el, <strong>de</strong>ntro <strong>de</strong>l evento Load.<br />

36


<strong>ControlsSAP</strong> Framework ®<br />

'Creación <strong>de</strong>l objeto <strong>de</strong> negocio y obtención <strong>de</strong> los datos<br />

_obj = New Contract(_company)<br />

Me.GetAllObjects(_obj)<br />

Me.GoToLast()<br />

4.3 Entrada/Salida <strong>de</strong> datos<br />

Listado 16: Carga <strong>de</strong> datos en el objeto <strong>de</strong> negocio.<br />

El formulario dispondrá <strong>de</strong> 2 métodos que <strong>de</strong>beremos sobrescribir y que necesitaremos para<br />

realizar la entrada <strong>de</strong> datos <strong>de</strong>l objeto hacia el formulario como el proceso contrario.<br />

Deberemos sobrescribir el LoadFormWithObject que se ejecutará cada vez que se necesite<br />

cargar datos en los controles <strong>de</strong>s<strong>de</strong> el objeto actual:<br />

Public Overri<strong>de</strong>s Sub LoadFormWithObject()<br />

txtCo<strong>de</strong>.Text = Me._obj.Co<strong>de</strong><br />

lstCardCo<strong>de</strong>.SelectedValue = Me._obj.CardCo<strong>de</strong><br />

txtDataIn.Text = Me._obj.DataIn<br />

txtDateOut.Text = Me._obj.DateOut<br />

txtComments.Text = Me._obj.Comments<br />

'Carga <strong>de</strong> las líneas<br />

grdCnt1.ObjectSource = Me._obj.Cnt1<br />

End Sub<br />

Para el proceso contrario, cargar los datos entrados en el formulario en las propieda<strong>de</strong>s <strong>de</strong>l<br />

objeto sobrescribiremos el método LoadObjectWithForm. Este se ejecutara en el momento <strong>de</strong><br />

añadir o actualizar:<br />

Public Overri<strong>de</strong>s Sub LoadObjectWithForm()<br />

Me._obj.CardCo<strong>de</strong> = lstCardCo<strong>de</strong>.SelectedValue<br />

Me._obj.DataIn = txtDataIn.Value<br />

Me._obj.DateOut = txtDateOut.Value<br />

Me._obj.Comments = txtComments.Text<br />

End Sub<br />

Hay que observar que las líneas no necesitan actualizarse ya que al trabajarse con la Grid se<br />

actualizan directamente en su origen <strong>de</strong> datos, por lo que el objeto dispondrá <strong>de</strong> los nuevos<br />

valores en todo momento.<br />

Con esto ya estaríamos en disposición <strong>de</strong> po<strong>de</strong>r realizar ya un mantenimiento básico <strong>de</strong> nuestro<br />

objeto. Por lo que si añadimos una nueva opción <strong>de</strong> menú en la que abramos el formulario<br />

podremos ya realizar altas, modificaciones, búsquedas, etc.<br />

37


<strong>ControlsSAP</strong> Framework ®<br />

Figura 5: Ejemplo formulario <strong>de</strong> edición en tiempo <strong>de</strong> ejecución.<br />

4.4 Trabajar con las grids<br />

Para completar nuestro mantenimiento con las líneas, <strong>de</strong>beremos realizar algunas validaciones,<br />

y completar algunos datos como por ejemplo: en el caso <strong>de</strong> entrar un código <strong>de</strong> artículo<br />

querremos que nos aparezca automáticamente la <strong>de</strong>scripción. Para ello necesitaremos capturar<br />

un evento <strong>de</strong> la grid que nos informe que se ha modificado y actualizar la propiedad <strong>de</strong> la línea<br />

correspondiente.<br />

Private Sub grdCnt1_UpdateSAPLine(ByVal l As <strong>ControlsSAP</strong>.SAPLines,<br />

ByVal ColumnName As String) Handles grdCnt1.UpdateSAPLine<br />

If ColumnName = "U_GSP_ItemCo<strong>de</strong>" Then<br />

Dim it As SAPbobsCOM.Items<br />

it = Me._company.GetBusinessObject(oItems)<br />

it.GetByKey(Me._obj.Cnt1.ItemCo<strong>de</strong>)<br />

'Actualizamos la <strong>de</strong>scripción<br />

Me._obj.Cnt1.ItemName = it.ItemName<br />

End If<br />

End Sub<br />

Para validar por ejemplo que la cantidad inicial sea siempre menor que la cantidad final<br />

haríamos lo siguiente:<br />

38


<strong>ControlsSAP</strong> Framework ®<br />

Private Sub grdCnt1_ValidateSAPLine(ByVal l As <strong>ControlsSAP</strong>.SAPLines, _<br />

ByVal e As DevExpress.XtraGrid.Views.Base.RowAllowEventArgs) Handles<br />

grdCnt1.ValidateSAPLine<br />

With Me._obj.Cnt1<br />

If .QuantIn > .QuantOut Then<br />

<strong>ControlsSAP</strong>.SAPMsg.StatusBarMsg("La cantidad inicial<br />

<strong>de</strong>be <strong>de</strong> ser mayor que la cantidad final", True)<br />

e.Allow = False<br />

End If<br />

End With<br />

End Sub<br />

Es recomendable que todas las validaciones que <strong>de</strong>bamos realizar sobre los objetos <strong>de</strong><br />

negocio se realicen <strong>de</strong>ntro <strong>de</strong>l propio objeto. Ya que si en otro momento lo utilizamos sin el<br />

formulario correspondiente, nos servirán las mismas validaciones y cumpliremos en cualquier<br />

entorno las reglas <strong>de</strong> negocio siempre.<br />

39


<strong>ControlsSAP</strong> Framework ®<br />

5 Impresiones<br />

El Framework <strong>de</strong> <strong>ControlsSAP</strong> dispone <strong>de</strong> utilida<strong>de</strong>s para facilitar el trabajo con informes<br />

realizados con la herramienta Cystal Reports. Esto facilita la incorporación <strong>de</strong> informes en las<br />

aplicaciones realizadas.<br />

5.1 Objeto Report<br />

Existe un objeto Report que po<strong>de</strong>mos utilizar para imprimir, previsualizar, exportar a <strong>pdf</strong>, etc.,<br />

informes creados con la herramienta <strong>de</strong> Crystal Reports.<br />

Las propieda<strong>de</strong>s y métodos mas usados para este tipo <strong>de</strong> objeto son:<br />

• ReportName: Indicaremos la ruta <strong>de</strong>l fichero “rpt”. El informe <strong>de</strong>berá estar <strong>de</strong>ntro <strong>de</strong> la<br />

ruta especificada en el formulario <strong>de</strong> configuración (Figura 6).<br />

• SetParameterValue: Si el informe contiene parámetros podremos indicarle los valores<br />

a estos mediante este método.<br />

• Print: Realiza la impresión <strong>de</strong>l informe indicado en la propiedad ReportName. Si el<br />

informe incluye parámetros y no hemos indicado sus valores aparecerá un formulario<br />

<strong>de</strong> <strong>de</strong>manda (Figura 7). También se mostrará un dialogo <strong>de</strong> impresión para especificar<br />

la impresora y el numero <strong>de</strong> copias (Figura 8). Si no queremos imprimir directamente<br />

por una impresora sin mostrar el dialogo <strong>de</strong> impresión entonces utilizaremos el método<br />

DirectPrint.<br />

• DirectPrint: Realiza la impresión directa <strong>de</strong>l informe. Funcionará igual que el método<br />

Print pero sin mostrar el dialogo <strong>de</strong> impresión. Deberemos especificar una impresora y<br />

el número <strong>de</strong> copias. Si no especificamos ninguna se imprimirá una copia por la<br />

impresora por <strong>de</strong>fecto.<br />

• Preview: Realizará una impresión preliminar. Si el informe incluye parámetros y no<br />

hemos indicado sus valores aparecerá un formulario <strong>de</strong> <strong>de</strong>manda.<br />

40


<strong>ControlsSAP</strong> Framework ®<br />

• SelectionFormula: Po<strong>de</strong>mos indicar una formula con formato <strong>de</strong> Crystal Reports para<br />

po<strong>de</strong>r filtrar los registros por el criterio indicado.<br />

En el constructor <strong>de</strong>beremos especificar el objeto SAPBobsCOM.Company. Este se utilizará<br />

para conectar la base <strong>de</strong> datos <strong>de</strong>l informe hacia la indicada en el objeto. Por lo que podremos<br />

reutilizar cualquier informe aunque este se haya creado con una conexión diferente.<br />

Es importante que realicemos la liberación <strong>de</strong>l objeto Report con el método Dispose. Para no<br />

tener problemas posteriores <strong>de</strong> memoria.<br />

Figura 6: Formulario <strong>de</strong> configuración. Especificar la ruta <strong>de</strong> los informes<br />

Figura 7: Formulario <strong>de</strong> <strong>de</strong>manda <strong>de</strong> parámetros<br />

41


<strong>ControlsSAP</strong> Framework ®<br />

5.2 Tipo <strong>de</strong> conexión<br />

Figura 8<br />

Al diseñar informes con Crystal Reports po<strong>de</strong>mos utilizar 2 tipos <strong>de</strong> conexión con la base <strong>de</strong><br />

datos, que serán compatibles con la impresión <strong>de</strong> <strong>ControlsSAP</strong>:<br />

• ODBC: Por <strong>de</strong>fecto <strong>ControlsSAP</strong> Framework ® creará una conexión <strong>de</strong> tipo ODBC que<br />

podremos utilizar para diseñar los informes con Crystal Reports. Po<strong>de</strong>mos<br />

consultar/modificar sus datos <strong>de</strong>s<strong>de</strong> Gestión Configuración.<br />

• OleDB (ADO): Podremos utilizar los informes creados con una conexión OleDB (ADO)<br />

para SQL Server.<br />

El sistema se encargará <strong>de</strong> reconocer que conexión utiliza el informe antes <strong>de</strong> actualizar los<br />

datos <strong>de</strong> conexión con la base <strong>de</strong> datos actual.<br />

5.3 Versiones Crystal Reports<br />

Po<strong>de</strong>mos diseñar informes que sean compatibles con las versiones <strong>de</strong> Crystal Reports 10 o<br />

Crystal Reports para NET 2.0 o la ultima versión <strong>de</strong> Crystal Reports 2008.<br />

El objeto Report lo podremos encontrar en una <strong>de</strong> las siguientes librerías, <strong>de</strong>pendiendo <strong>de</strong> que<br />

versión <strong>de</strong> Crystal Reports que necesitemos:<br />

• <strong>ControlsSAP</strong>.CrystalReports.v10.dll<br />

• <strong>ControlsSAP</strong>.CrystalReports.v12.dll<br />

42


<strong>ControlsSAP</strong> Framework ®<br />

Podremos utilizar una u otra, o las dos a la vez. En estas librerías encontraremos el objeto<br />

Report. El objeto lo encontraremos en el namespace:<br />

• <strong>ControlsSAP</strong>.CrystalReports .Cr10.Report<br />

• <strong>ControlsSAP</strong>.CrystalReports .Cr12.Report<br />

5.4 Visor <strong>de</strong> informes<br />

Cada visor incluirá su propia barra <strong>de</strong> herramientas, a<strong>de</strong>más podremos utilizar también la barra<br />

<strong>de</strong> herramientas <strong>de</strong> SAP o <strong>de</strong>l formulario <strong>de</strong> aplicación si estamos por fuera.<br />

5.5 Configurar informes en formularios<br />

Existen propieda<strong>de</strong>s y métodos en los formularios <strong>de</strong> tipo FormSAP, que nos permitirán añadir<br />

internamente informes para posteriormente po<strong>de</strong>rlos previsualizar o imprimir. También<br />

permitiremos añadir informes externamente a nivel <strong>de</strong> usuario, pudiendo duplicar informes<br />

existentes o añadiendo nuevos.<br />

Para utilizar esta nueva funcionalidad <strong>de</strong>beremos activar la propiedad UseSystemPrinting. Por<br />

<strong>de</strong>fecto esta propiedad estará a “False”, por lo que al pulsar sobre imprimir/previsualizar se<br />

ejecutará el método OnPrint y el evento PrintingForm. Pero si queremos utilizar esta<br />

funcionalidad esta propiedad <strong>de</strong>berá estar a “True”, y ya no se ejecutarán los métodos y<br />

eventos anteriormente mencionados.<br />

43


<strong>ControlsSAP</strong> Framework ®<br />

Para añadir un informe tenemos una propiedad Reports que nos permitirá añadir varios<br />

informes al formulario <strong>de</strong>l siguiente modo:<br />

Me.Reports.Add("Facturas", New cr12.Report(GetType(misfacturas),<br />

Me._company))<br />

Me.Reports.Add("Factura2", New cr12.Report(GetType(factura1),<br />

Me._company), _<br />

New CrystalReportsParameter("Co<strong>de</strong>",<br />

Me.txtCo<strong>de</strong>))<br />

Public Sub Add(Description as String,<br />

ReportObj AS <strong>ControlsSAP</strong>.CrystalReports.IReport,<br />

ParamArray Parameters CrystalReportsParameter())<br />

Description: Descripción que le daremos al informe. Deberá ser única para los informes <strong>de</strong>l<br />

formulario.<br />

ReportObj: Instanciaremos un objeto Report indicándole el tipo <strong>de</strong> la clase que hace referencia<br />

al informe CrystalReports, y la company <strong>de</strong>s<strong>de</strong> la que obtendrá los datos.<br />

Parameters: Lista <strong>de</strong> parámetros que queramos pasar a el informe en el momento <strong>de</strong><br />

imprimirlo. Los parámetros podrán ser <strong>de</strong> tipo Discreto o <strong>de</strong> tipo Rango. Necesitaremos indicar<br />

el nombre <strong>de</strong>l parámetro y <strong>de</strong> que control <strong>de</strong>l formulario obtendremos el valor. También<br />

podremos pasar valores constantes.<br />

Para po<strong>de</strong>r incluir informes <strong>de</strong>ntro <strong>de</strong> nuestros proyectos y así utilizarlos como una clase<br />

<strong>de</strong>beremos tener instalado alguna versión <strong>de</strong> Crystal Reports que incluya herramientas <strong>de</strong><br />

integración para Visual Studio.<br />

Po<strong>de</strong>mos obtener una <strong>de</strong>s<strong>de</strong> la herramienta <strong>de</strong> instalación <strong>de</strong> Visual Studio 2005, marcando la<br />

casilla Crystal Reports para Visual Studio que instalará las librerías para Crystal Reports 10<br />

(Figura 9).<br />

44


<strong>ControlsSAP</strong> Framework ®<br />

Figura 9: Crystal Reports para Visual Studio 2005<br />

Si tenemos esta funcionalidad ya podremos anexar documentos *.rpt en nuestro proyecto. Al<br />

anexarlos al proyecto automáticamente se generará una clase *.vb que utilizaremos para hacer<br />

referencia a estos informes.<br />

Con esto ya tendríamos <strong>de</strong>finidos varios informes <strong>de</strong> sistema. Ahora podríamos <strong>de</strong>finir otros<br />

informes <strong>de</strong> usuario, propios para cada tipo <strong>de</strong> cliente. Para ello utilizaremos el botón <strong>de</strong>l<br />

diseñador <strong>de</strong> layaouts <strong>de</strong> SAP (Figura 10: Diseñador <strong>de</strong> informes).<br />

45


<strong>ControlsSAP</strong> Framework ®<br />

Figura 10: Diseñador <strong>de</strong> informes<br />

Des<strong>de</strong> el diseñador podremos realizar las siguientes acciones:<br />

Fijar como estándar: Podremos <strong>de</strong>finir que formulario queremos fijar por <strong>de</strong>fecto.<br />

Podremos indicar si lo queremos para todos lo usuarios o solamente para el usuario actual.<br />

Si algún usuario tuviera una configuración propia no se le cambiaría si indicamos que lo<br />

queremos para todos los usuarios. Solamente afectara cuando el usuario no tenga ningún<br />

informe <strong>de</strong>finido por <strong>de</strong>fecto para el.<br />

Duplicar: Creará una copia <strong>de</strong>l informe seleccionado en un archivo rpt, en la ruta <strong>de</strong> los<br />

informes indicada en la configuración.<br />

Nuevo informe: Podremos añadir un nuevo informe <strong>de</strong> CrystalReports. Para ello<br />

<strong>de</strong>beremos indicar una <strong>de</strong>scripción que no se podrá repetir y seleccionar un informe rpt<br />

que creará una copia en la ruta <strong>de</strong> los reports.<br />

Una vez seleccionado el fichero con el report aparecerán los parámetros <strong>de</strong> este. Si<br />

queremos que el parámetro este relacionado con algún control <strong>de</strong>l formulario <strong>de</strong>beremos<br />

indicar el nombre <strong>de</strong> este control. Si por lo contrario queremos indicar un valor fijo se lo<br />

indicaremos entre llaves ({Valor}), y si lo <strong>de</strong>jamos en blanco entonces en el momento <strong>de</strong> la<br />

impresión se lo pedirá al usuario.<br />

También podremos indicar el número <strong>de</strong> copias por <strong>de</strong>fecto. Si indicamos una impresora<br />

fija se imprimirá directamente por ella, si lo <strong>de</strong>jamos en blanco en el momento <strong>de</strong> imprimir<br />

aparecerá el dialogo <strong>de</strong> impresión con la impresora por <strong>de</strong>fecto <strong>de</strong>l sistema.<br />

46


<strong>ControlsSAP</strong> Framework ®<br />

Figura 11: Añadir un nuevo informe.<br />

Editar: Permitirá editar una informe <strong>de</strong> usuario. Los informes <strong>de</strong> sistema no se pue<strong>de</strong>n<br />

modificar. Si queremos variar algún valor <strong>de</strong>beremos duplicar el informe y entonces editar<br />

el nuevo informe <strong>de</strong> usuario.<br />

Eliminar: Eliminaremos el informe <strong>de</strong> usuario seleccionado.<br />

Diseñar: Permite abrir el informe para su diseño siempre y cuando tengamos las<br />

herramienta <strong>de</strong> Crystal Reports instalada en la máquina.<br />

Una vez configurados los informes si pulsamos previsualizar nos aparecerá una lista con los<br />

informes incluidos en el formulario.<br />

Si pulsamos el botón <strong>de</strong> imprimir , imprimiremos el informe consi<strong>de</strong>rado por <strong>de</strong>fecto.<br />

47


<strong>ControlsSAP</strong> Framework ®<br />

6 Mensaje <strong>de</strong> sistema<br />

Disponemos <strong>de</strong> una serie <strong>de</strong> mensajes <strong>de</strong> sistema con la apariencia <strong>de</strong> SAP Business One, para<br />

facilitar la comunicación entre el usuario y la aplicación.<br />

Existirán diferentes tipos <strong>de</strong> mensajes:<br />

• Informativo<br />

• Aviso<br />

• Decisión<br />

• Error<br />

• Acción<br />

• Entrada <strong>de</strong> datos<br />

6.1 Mensajes <strong>de</strong> dialogo<br />

Existen una serie <strong>de</strong> mensajes ya <strong>de</strong>finidos según el tipo <strong>de</strong> mensaje que queramos mostrar:<br />

Ico Tipo<br />

SAPMsg.Question<br />

SAPMsg.Alert<br />

SAPMsg.Critical/Exception<br />

SAPMsg.Info<br />

Po<strong>de</strong>mos configurar nuestro propio mensaje con la función SAPMsg.Show indicando el<br />

mensaje, el icono, los botones.<br />

Pulsando al aparecen una mensaje <strong>de</strong>l tipo SAPMsg, podremos copiar el texto <strong>de</strong>l<br />

mensaje.<br />

48


<strong>ControlsSAP</strong> Framework ®<br />

Para utilizar mensajes que muestren excepciones capturadas po<strong>de</strong>mos utilizar la función<br />

SAPMsg.Show y pasarle la excepción. Este tipo <strong>de</strong> mensajes permite que haciendo doble clic<br />

sobre el mensaje <strong>de</strong> error, po<strong>de</strong>r visualizar la pila <strong>de</strong> la excepción (Figura 12: Mensaje<br />

mostrando la excepción completa.).<br />

Figura 12: Mensaje mostrando la excepción completa.<br />

6.2 Mensajes en la barra <strong>de</strong> estado<br />

También se han añadido los 3 tipos <strong>de</strong> mensaje que se pue<strong>de</strong>n indicar en la barra <strong>de</strong> estado<br />

mediante la función SAPMsg.StatusBar.<br />

6.3 InputBox<br />

49<br />

Confirmación/Success<br />

Error<br />

Información/Warning<br />

Este tipo <strong>de</strong> mensaje <strong>de</strong> sistema nos permitirá obtener un valor <strong>de</strong>l usuario con el método<br />

<strong>ControlsSAP</strong>.SAPMsg.InputBox.


<strong>ControlsSAP</strong> Framework ®<br />

Figura 13: Ejemplo InputBox <strong>de</strong> tipo fecha.<br />

Dim d As DateTime<br />

d = SAPMsg.InputBox( _<br />

"Hasta que fecha quieres eliminar los registros <strong>de</strong>l 'Log <strong>de</strong><br />

modificaciones'", _<br />

SAPMsg.InputType.Date, Today)<br />

50


<strong>ControlsSAP</strong> Framework ®<br />

7 Autorizaciones<br />

<strong>ControlsSAP</strong> Framework proporciona una serie <strong>de</strong> funcionalida<strong>de</strong>s integradas con SAP Business<br />

One que permiten <strong>de</strong>finir autorizaciones <strong>de</strong> usuario para mostrar o no las pantallas <strong>de</strong>finidas<br />

con la herramienta. Estas autorizaciones se configurarán <strong>de</strong>s<strong>de</strong> el formulario <strong>de</strong> autorizaciones<br />

<strong>de</strong> SAP Business One.<br />

7.1 Definición<br />

Al arrancar un módulo <strong>de</strong> trabajo, se generará una autorización <strong>de</strong> usuario, por cada formulario<br />

que cargue nuestra aplicación <strong>de</strong> manera automática.<br />

Estas autorizaciones se modificarían <strong>de</strong>s<strong>de</strong> la pantalla <strong>de</strong> SAP Gestión Inicialización sistema<br />

Autorizaciones Autorizaciones generales, <strong>de</strong>s<strong>de</strong> las autorizaciones <strong>de</strong> usuario (Figura 14).<br />

Será necesario <strong>de</strong>finir un atributo por cada formulario con una <strong>de</strong>scripción (máximo 40<br />

caracteres) que <strong>de</strong>fina el formulario. Si no se especifica ningún atributo la <strong>de</strong>scripción <strong>de</strong> la<br />

autorización será la misma que el nombre <strong>de</strong>l formulario. El atributo que utilizaremos será<br />

<strong>ControlsSAP</strong>.Forms.FormDescription.<br />

Por <strong>de</strong>fecto todos los formularios estarán controlados mediante autorizaciones. Si queremos<br />

que un formulario <strong>de</strong>terminado no este sujeto a ningún tipo <strong>de</strong> autorización (podrá abrirlo<br />

cualquier usuario) utilizaremos el atributo <strong>ControlsSAP</strong>. Authorizations.AuthorizationExempt.<br />

51


<strong>ControlsSAP</strong> Framework ®<br />

Figura 14<br />

Por <strong>de</strong>fecto todas las autorizaciones nuevas que se creen lo harán por <strong>de</strong>fecto con<br />

“Autorización total”.<br />

7.2 Creación<br />

De momento para que se creen automáticamente las autorizaciones <strong>de</strong> todos los formularios<br />

<strong>de</strong> una librería, es necesario cambiar el AssemblyDataBaseVersion para provocar una<br />

actualización y que exista en el modulo algún objeto para crear en la base <strong>de</strong> datos ya sea una<br />

tabla, campo, vista, etc. <strong>de</strong>s<strong>de</strong> el FormDLL (ver capitulo Módulos <strong>de</strong> trabajo).<br />

Existirá una opción en el menú administrador, para crear/actualizar estas autorizaciones, <strong>de</strong><br />

manera manual.<br />

52


<strong>ControlsSAP</strong> Framework ®<br />

8 Parámetros<br />

Existe una clase por la que po<strong>de</strong>mos crear <strong>de</strong> una manera fácil objetos que contendrán una lista<br />

<strong>de</strong> parámetros que nos pue<strong>de</strong> servir para la parametrización <strong>de</strong>l módulo. Sin la necesidad <strong>de</strong><br />

crear nuevos objetos y ni tablas en la base <strong>de</strong> datos.<br />

Estos se podrán modificar ya sea <strong>de</strong>s<strong>de</strong> el propio objeto o por el usuario <strong>de</strong> la aplicación<br />

mediante el formulario <strong>de</strong> Parámetros en el menú Gestión.<br />

8.1 Creación <strong>de</strong> parámetros<br />

Nuestros módulos podrán tener una lista <strong>de</strong> parámetros con los que po<strong>de</strong>r interactuar. Para<br />

ello <strong>de</strong>finiremos en nuestro proyecto una clase que here<strong>de</strong> <strong>de</strong><br />

<strong>ControlsSAP</strong>.Parameters.ApplicationParameters y <strong>de</strong>finiremos una lista <strong>de</strong> variables, cada una<br />

con el atributo <strong>ControlsSAP</strong>.Parameters.ParameterAttribute. Don<strong>de</strong> podremos especificar:<br />

• El tipo <strong>de</strong> parámetro que normalmente coincidirá con el tipo <strong>de</strong> la variable.<br />

• El nombre <strong>de</strong>l parámetro (opcional).<br />

• Descripción.<br />

• Valor por <strong>de</strong>fecto.<br />

• Visibilidad <strong>de</strong>l parámetro. Si es un parámetro <strong>de</strong> sistema solamente será posible<br />

modificarlo entrando en la aplicación en modo Administrador.<br />

• Comentarios.<br />

Po<strong>de</strong>mos indicar al parámetro datos extras mediante otros atributos como Data y Mask:<br />

• Una sentencia SQL con los valores validos para el parámetro.<br />

• Una lista <strong>de</strong> valores que serán los valores validos que pue<strong>de</strong> aceptar el<br />

parámetro.<br />

53


<strong>ControlsSAP</strong> Framework ®<br />

• Una mascara <strong>de</strong> entrada <strong>de</strong> datos.<br />

Po<strong>de</strong>mos ver un ejemplo <strong>de</strong> cómo <strong>de</strong>finir una clase con 2 parámetros:<br />

Imports <strong>ControlsSAP</strong><br />

Imports <strong>ControlsSAP</strong>.Parameters<br />

Imports <strong>ControlsSAP</strong>.Parameters.ParameterType<br />

Public Class Parametros1<br />

Inherits <strong>ControlsSAP</strong>.Parameters.ApplicationParameters<br />

Public Sub New(ByVal c As SAPbobsCOM.Company)<br />

MyBase.New(c)<br />

End Sub<br />

' Cantidad inicial<br />

_<br />

Public CANTINI As Integer<br />

' Ruta plantillas<br />

_<br />

Public PATHPLANT As String<br />

End Class<br />

Ejemplos para indicar un origen <strong>de</strong> datos con el atributo <strong>ControlsSAP</strong>.Parameters.Data. El<br />

origen podrá ser una sentencia SQL, o una lista <strong>de</strong> valores <strong>de</strong>l mismo tipo <strong>de</strong>finido en la<br />

variable:<br />

'Valores posibles: Numeros par <strong>de</strong>l 0 al 20<br />

_<br />

_<br />

Public NumeroPar As Integer<br />

'Valores posibles: Las listas <strong>de</strong> precios<br />

_<br />

_<br />

Public ListaPrecios<br />

54


<strong>ControlsSAP</strong> Framework ®<br />

Existe otro tipo <strong>de</strong> atributo <strong>ControlsSAP</strong>.Parameters.Mask. Con los que podremos <strong>de</strong>finir<br />

mascaras con expresiones regulares, para la entrada <strong>de</strong> datos <strong>de</strong>s<strong>de</strong> el formulario <strong>de</strong><br />

parámetros.<br />

Ejemplo:<br />

'Solamente se podrán introducir direcciones ftp<br />

_<br />

_<br />

Public DireccionFtp As String<br />

8.2 Utilización <strong>de</strong> parametros<br />

Para modificar los valores lo podremos hacer <strong>de</strong>s<strong>de</strong> código o mediante el formulario <strong>de</strong> edición<br />

<strong>de</strong> parámetros (Figura 15) que hay en Gestión Parámetros, don<strong>de</strong> estarán todos los<br />

parámetros <strong>de</strong> los módulos añadidos.<br />

Dim p As Parametros1<br />

p = New Parametros1 (c)<br />

p. PATHPLANT="C:\Plantillas\Demo"<br />

p.Save()<br />

Para que nuestra clase parámetros aparezca en el formulario <strong>de</strong> edición <strong>de</strong> parámetros que<br />

trae el framework <strong>de</strong> <strong>ControlsSAP</strong> y podamos editarlos es necesario que en algún momento <strong>de</strong>l<br />

arranque <strong>de</strong> la aplicación, registremos una instancia <strong>de</strong> nuestra clase con:<br />

<strong>ControlsSAP</strong>.Register.Parameter(ApplicationParameter)<br />

Public Overri<strong>de</strong>s Sub Run()<br />

...<br />

<strong>ControlsSAP</strong>.Register.Parameter(DLL.GetParameters(c))<br />

End Sub<br />

55


<strong>ControlsSAP</strong> Framework ®<br />

Figura 15<br />

Des<strong>de</strong> la clase ApplicationParameters, don<strong>de</strong> <strong>de</strong>finimos los parámetros <strong>de</strong> nuestro módulo,<br />

podremos indicarle al constructor el nombre <strong>de</strong> una categoría por la que se agruparán los<br />

parámetros <strong>de</strong> un mismo módulo, cuando se muestren <strong>de</strong>s<strong>de</strong> el formulario <strong>de</strong> parámetros<br />

(Figura 16).<br />

Public Class ParemetersDemo<br />

Inherits <strong>ControlsSAP</strong>.Parameters.ApplicationParameters<br />

Public Sub New(ByVal c As SAPbobsCOM.Company)<br />

MyBase.New(c, "Demo Categoria")<br />

End Sub<br />

...<br />

56


<strong>ControlsSAP</strong> Framework ®<br />

Figura 16<br />

Por lo que podremos tener registrados en un mismo módulo/librería varias clases <strong>de</strong><br />

parámetros. Que se localizarán en la misma pestaña y se agruparán por las categorías indicadas.<br />

57<br />

Grupo 1<br />

Grupo 2


<strong>ControlsSAP</strong> Framework ®<br />

9 Módulos <strong>de</strong> trabajo<br />

Nuestras aplicaciones pue<strong>de</strong>n crear en el arranque varios tipos <strong>de</strong> objetos newcesarios<br />

para el inicio <strong>de</strong> la aplicación, como son:<br />

• Objetos que se <strong>de</strong>ben crear en la base <strong>de</strong> datos (tablas, vistas, campos,<br />

búsquedas formateadas, etc.)<br />

• Opciones <strong>de</strong> menú<br />

• Lista <strong>de</strong> Parámetros<br />

• Autorizaciones para los formularios<br />

Que <strong>de</strong>jarán la aplicación preparada para comenzar a trabajar con ella sin la necesidad<br />

<strong>de</strong> realizar ninguna acción extra.<br />

Modulo<br />

Versión DLL<br />

Versión Fichero<br />

Versión DB: 2009.0.0.0<br />

Parámetros Autorizaciones<br />

58<br />

Menús<br />

Objetos <strong>de</strong>finidos<br />

en la base <strong>de</strong><br />

datos


<strong>ControlsSAP</strong> Framework ®<br />

9.1 Creación <strong>de</strong> un módulo<br />

Para crear nuestro modulo <strong>de</strong>beremos utilizar un objeto <strong>de</strong> tipo formulario, que<br />

utilizaremos para <strong>de</strong>finir el menú <strong>de</strong> la aplicación y sus objetos a crear en la base <strong>de</strong> datos.<br />

Tendremos que crear un formulario <strong>de</strong>l tipo ContolsSAP.Forms.FormDLL. Utilizaremos<br />

el diseñador <strong>de</strong>l formulario para crear el menú <strong>de</strong> nuestro modulo añadiendo varios MenuStrip<br />

para cada tipo <strong>de</strong> menú.<br />

9.2 Creación <strong>de</strong> los Menús<br />

Un módulo podrá constar <strong>de</strong> 3 tipos diferentes <strong>de</strong> menús:<br />

• Menú <strong>de</strong> aplicación: Será el menú principal que utilizará el usuario <strong>de</strong> la<br />

aplicación.<br />

• Menú <strong>de</strong>finición: Este es el menú que aparecerá <strong>de</strong>ntro <strong>de</strong>l menú Gestión<br />

Definición y que utilizaremos para añadir las opciones referentes a la creación<br />

<strong>de</strong> datos maestros. Parecido al menú que <strong>de</strong>finición que aparece en SAP.<br />

• Menú administrador: Este menú solamente lo podrán visualizar los<br />

<strong>programador</strong>es y nos servirá para ocultar <strong>de</strong>terminadas opciones al usuario.<br />

Para diseñar cada tipo <strong>de</strong> menú utilizaremos el control MenuStrip (propios <strong>de</strong> .NET)<br />

según nuestras necesida<strong>de</strong>s.<br />

En cada MenuStrip añadido podremos <strong>de</strong>finir una o varias opciones <strong>de</strong> menú y<br />

submenús.<br />

Existirá 3 propieda<strong>de</strong>s en la clase FormDLL para especificar si el menú es <strong>de</strong> aplicación,<br />

<strong>de</strong>finición o <strong>de</strong> administrador:<br />

• MenuAdminStrip<br />

• MenuApplicationStrip<br />

• MenuDefinitionStrip<br />

59


<strong>ControlsSAP</strong> Framework ®<br />

9.3 Creación <strong>de</strong> la base <strong>de</strong> datos<br />

Nuestro modulo necesitará <strong>de</strong>finir una serie <strong>de</strong> objetos en la base <strong>de</strong> datos <strong>de</strong> SAP para<br />

funcionar correctamente. Los objetos se crearán la primera vez que arranque el módulo o<br />

cuando se <strong>de</strong>tecte un cambio <strong>de</strong> versión lo que provocará que se creen o actualicen aquellos<br />

objetos que se han añadido o modificado.<br />

En próximos capítulos veremos más extensamente que objetos utilizaremos para crear tablas,<br />

campos, vista, etc.… en la base <strong>de</strong> datos.<br />

60


<strong>ControlsSAP</strong> Framework ®<br />

Des<strong>de</strong> nuestro formulario iremos añadiendo todos los objetos necesarios para po<strong>de</strong>r ejecutar<br />

nuestro modulo y en el momento <strong>de</strong>l arranque estos se crearán si es necesario. Para esto existe<br />

la propiedad DataBase que nos proporciona un objeto <strong>de</strong> tipo lista, para ir añadiendo tablas,<br />

campos y <strong>de</strong>más objetos que <strong>de</strong>berá crear nuestro modulo al arrancar o al cambiar <strong>de</strong> versión.<br />

Deberemos sobrescribir el método CreateDataBaseObjects() e ir añadiendo las tablas y<br />

campos. Los objetos se <strong>de</strong>finirán igual que lo haríamos <strong>de</strong>s<strong>de</strong> el diseñador <strong>de</strong> SAP (sin el ‘@’<br />

<strong>de</strong>lante <strong>de</strong> las tablas y sin el ‘U_’ <strong>de</strong>lante <strong>de</strong> los campos).<br />

Definiremos 2 tablas con sus diferentes campos:<br />

Public Overri<strong>de</strong>s Sub CreateDataBaseObjects()<br />

MyBase.CreateDataBaseObjects()<br />

With Me.DataBase.AddTable("GSP_CNTR", "Contratos").Fields<br />

.AddAlfanumerico("GSP_CardCo<strong>de</strong>", "Código cliente", 50)<br />

.AddAlfanumerico("GSP_CardName", "Nombre", 100)<br />

.AddFecha("GSP_DataIn", "Fecha inicio")<br />

.AddFecha("GSP_DateOut", "Fecha <strong>de</strong> fin")<br />

.AddMemo("GSP_Comments", "Comentarios")<br />

End With<br />

With Me.DataBase.AddTable("GSP_CNT1", "Lineas <strong>de</strong><br />

contratos").Fields<br />

.AddAlfanumerico("GSP_CntrCo<strong>de</strong>", "Cód.contrato", 8)<br />

.AddAlfanumerico("GSP_ItemCo<strong>de</strong>", "Cod. Artículo", 50)<br />

.AddAlfanumerico("GSP_ItemName", "Descripción", 150)<br />

.AddCantidad("GSP_QuantIn", "Cantidad inicial")<br />

.AddCantidad("GSP_QuantOut", "Cantidad final")<br />

.AddImporte("GSP_Import", "Importe")<br />

End With<br />

End Sub<br />

Po<strong>de</strong>mos añadir a la lista objetos <strong>de</strong> tipo:<br />

• Tablas: <strong>de</strong>ntro <strong>de</strong> cada tabla po<strong>de</strong>mos añadir objetos como campos, valores validos, e<br />

índices.<br />

• Vistas<br />

• Procedimientos almacenados<br />

• Acciones SQL: como inserts, updates, <strong>de</strong>letes.<br />

• Categorías SAP: <strong>de</strong>ntro <strong>de</strong> cada categoría po<strong>de</strong>mos <strong>de</strong>finir búsquedas formateadas,<br />

consultas pre<strong>de</strong>finidas.<br />

61


<strong>ControlsSAP</strong> Framework ®<br />

9.4 Control <strong>de</strong> versiones<br />

Para el control <strong>de</strong> versiones existe un mecanismo mediante un atributo <strong>de</strong> ensamblado por el<br />

cual el <strong>programador</strong> podrá modificar e indicará que el modulo en cuestión <strong>de</strong>be ser actualizado.<br />

Este se <strong>de</strong>berá indicar en el archivo AssemblyInfo <strong>de</strong>l proyecto.<br />

<br />

En el momento <strong>de</strong> arrancar se <strong>de</strong>tectará si se ha modificado la versión o si es un nuevo módulo<br />

por lo que se avisará al usuario que se van a ejecutar modificaciones en SAP. De esta manera no<br />

hará falta que el consultor o los usuarios <strong>de</strong> SAP sepan que campos o tablas se tienen que crear<br />

en una nueva versión.<br />

9.5 Creación <strong>de</strong> parámetros<br />

Nuestros módulos podrán tener una o varias listas <strong>de</strong> parámetros con los que po<strong>de</strong>r<br />

interactuar.<br />

Para que nuestras clases <strong>de</strong> parámetros estén disponibles <strong>de</strong>s<strong>de</strong> el formulario <strong>de</strong> edición que<br />

trae el framework <strong>de</strong> <strong>ControlsSAP</strong> es necesario que en algún momento <strong>de</strong> la carga inicial<br />

registremos una instancia <strong>de</strong> nuestra clase con:<br />

<strong>ControlsSAP</strong>.Register.Parameter(ApplicationParameter)<br />

Ejemplo <strong>de</strong> registro <strong>de</strong> los parámetros <strong>de</strong>s<strong>de</strong> la carga <strong>de</strong>l pluggin.<br />

Public Overri<strong>de</strong>s Sub Run()<br />

...<br />

<strong>ControlsSAP</strong>.Register.Parameter(DLL.GetParameters(c))<br />

End Sub<br />

62


<strong>ControlsSAP</strong> Framework ®<br />

9.6 Arranque <strong>de</strong> un módulo <strong>de</strong> trabajo<br />

Una vez creado el formulario que contendrá el módulo <strong>de</strong>finiremos una clase (por norma<br />

general se llamará DLL) con un método –LoadDLL- que retornará un objeto LibraryDLL que<br />

utilizaremos mas a<strong>de</strong>lante.<br />

Public Class DLL<br />

Public Shared Function GetParameters(ByVal c As Company) As<br />

Parametros1<br />

Return New ParemetersDemo(c)<br />

End Function<br />

Public Shared Function LoadDLL(ByVal c As SAPbobsCOM.Company) As<br />

<strong>ControlsSAP</strong>.Forms.FormDLL.LibraryDLL<br />

<strong>ControlsSAP</strong>.Register.Parameter(DLL.GetParameters(c))<br />

Dim f As New frmDLL(c)<br />

Return f.GetMenuDLL<br />

End Function<br />

End Class<br />

Después si lo que queremos el cargar el modulo creado <strong>de</strong>ntro <strong>de</strong> SAP Business One crearemos<br />

un Pluggin y en el momento <strong>de</strong> ejecutar el Run realizaremos 3 acciones:<br />

1. Conectaremos al AddOn mediante AddOnConnection()<br />

63


<strong>ControlsSAP</strong> Framework ®<br />

2. Cargaremos los módulos que necesite nuestra aplicación<br />

(AddModule/AddItemsModule)<br />

3. Arrancaremos una aplicación que creará un nuevo punto <strong>de</strong> menú en SAP B1<br />

incluyendo las opciones <strong>de</strong> menú <strong>de</strong> los módulos cargados hasta ese momento.<br />

Imports <strong>ControlsSAP</strong><br />

Imports <strong>ControlsSAP</strong>.SapUI<br />

_<br />

Public Class WinFormDemoPlugin<br />

Inherits Addon2Core.PluginEngine.CPlugin<br />

Public Overri<strong>de</strong>s Sub Run()<br />

Try<br />

End Sub<br />

End Class<br />

'Conecta la libreria <strong>ControlsSAP</strong> con el AddOn<br />

AddOn.AddonConnection()<br />

'Carga <strong>de</strong> los modulos que tendra nuestra<br />

'aplicación en SAP Business One<br />

AddOn.AddItemsModule( _<br />

DLL.LoadDLL(Addon2Core.Addon.CB1App.Company))<br />

'Arranca una aplicación con los módulos<br />

'cargados hasta ese momento<br />

<strong>ControlsSAP</strong>.SapUI.AddOn.Start("SBO_OneDemo2")<br />

Catch ex As Exception<br />

SapMsg.Show(ex)<br />

End Try<br />

64


<strong>ControlsSAP</strong> Framework ®<br />

65


<strong>ControlsSAP</strong> Framework ®<br />

10 Integración<br />

10.1 Estilo 8.8<br />

Las pantallas se repintarán según el estilo elegido en SAP Business One. Sin la necesidad <strong>de</strong><br />

realizar ninguna modificación <strong>de</strong>s<strong>de</strong> el diseñador <strong>de</strong> código.<br />

• Estilo clásico:<br />

• Nuevo Estilo 8.8:<br />

66


<strong>ControlsSAP</strong> Framework ®<br />

10.2 Fuente, tamaño <strong>de</strong> letra y color <strong>de</strong> las pantallas<br />

En el momento <strong>de</strong> abrirse los formularios se mostrarán con la configuración <strong>de</strong> fuente y color<br />

establecidos en SAP Business One.<br />

En modo diseño se continuaría diseñando las pantallas tal y como hasta ahora. Para que se<br />

pueda utilizar esta nueva funcionalidad el formulario <strong>de</strong>be tener la propiedad AutoScaleMo<strong>de</strong><br />

a Font. Por <strong>de</strong>fecto los formularios ya se crean con este valor.<br />

10.3 Textos Dinámicos (Control + Doble-Click)<br />

Se podrán modificar los textos <strong>de</strong> las etiquetas <strong>de</strong> algunos controles, tal y como hace SAP,<br />

pulsando {CONTROL} y haciendo DOBLE-CLICK con el ratón.<br />

Los controles con esta función habilitada serán:<br />

• SAPLabel (etiquetas)<br />

• SAPTabPage (Pestañas)<br />

• SAPRadioButton/SAPCheckBox<br />

• Columnas <strong>de</strong> la grid<br />

Esta funcionalidad se grabará en la base <strong>de</strong> datos don<strong>de</strong> se conecte por <strong>de</strong>fecto el AddOn.<br />

67


<strong>ControlsSAP</strong> Framework ®<br />

10.4 Menús para SAP Business One<br />

Para crear nuestro menú <strong>de</strong> aplicación <strong>de</strong>s<strong>de</strong> el formulario FormDLL existirá un tipo <strong>de</strong> control<br />

que nos permitirá añadir la opción <strong>de</strong> menú <strong>de</strong>ntro <strong>de</strong> unas coor<strong>de</strong>nadas específicas en el<br />

menú <strong>de</strong> SAP.<br />

La propiedad que utilizaremos para ello será SapLocation <strong>de</strong>s<strong>de</strong> la que podremos especificar:<br />

• ParentUID: I<strong>de</strong>ntificador <strong>de</strong>l menú padre <strong>de</strong> la que colgara nuestra opción. Si no se<br />

especifica ningún valor, se pintará la opción en su lugar por <strong>de</strong>fecto. Si se especifica 0 o<br />

el valor 43520 se añadirá en el menú raíz.<br />

• Position: Posición que ocupará nuestra opción <strong>de</strong>ntro <strong>de</strong> las opciones que cuelgan <strong>de</strong><br />

menú indicado en el ParentUID. Si la posición es -1, la opción se añadirá al final.<br />

Para po<strong>de</strong>r utilizar este nuevo control en opciones ya creadas, po<strong>de</strong>mos convertir la opción <strong>de</strong><br />

menú a SAPMenuItem fácilmente. Des<strong>de</strong> la opción “Convertir en...” en el menú contextual que<br />

existe en el diseñador <strong>de</strong> menús <strong>de</strong> Visual Studio haciendo clic <strong>de</strong>recho sobre el control.<br />

68<br />

Nuevo tipo <strong>de</strong> menú


<strong>ControlsSAP</strong> Framework ®<br />

11 Database<br />

En este capitulo veremos una serie <strong>de</strong> objetos que po<strong>de</strong>mos crear en la base <strong>de</strong> datos <strong>de</strong> SAP<br />

Business One. Todos ellos implementan una interficie que incluye un método Execute. Que<br />

sirve para crear/actualizar el objeto en la base <strong>de</strong> datos.<br />

Si necesitamos crear en un momento dado cualquiera <strong>de</strong> estos objetos utilizaríamos este<br />

método. Pero lo normal será que se creen los objetos en el momento <strong>de</strong> arranque <strong>de</strong>l módulo.<br />

Y para ello en vez <strong>de</strong> utilizar el método Execute lo que haríamos es añadir los objetos en la<br />

colección FormDLL.DataBase <strong>de</strong>ntro <strong>de</strong>l método FormDLL.CreateDataBaseObjects.<br />

11.1 Tablas, campos, índices<br />

Po<strong>de</strong>mos crear tablas en SAP Business One con el objeto SAPUserTable. Indicándole un nombre<br />

y una <strong>de</strong>scripción.<br />

11.1.1 Campos<br />

Para <strong>de</strong>finir los campos utilizaremos la colección Fields.<br />

Po<strong>de</strong>mos <strong>de</strong>finir campos con los métodos siguientes:<br />

• AddAlfanumerico: Aña<strong>de</strong> un campo <strong>de</strong> tipo alfanumérico.<br />

• AddBooleano: Aña<strong>de</strong> un campo alfanumérico <strong>de</strong> longitud 1 carácter, con los valores<br />

válidos (Y)es/(N)o.<br />

• AddCantidad: <strong>de</strong>fine un campo <strong>de</strong> tipo cantidad.<br />

• AddImporte: crea un campo en la tabla <strong>de</strong> tipo importe.<br />

• AddPrecio: <strong>de</strong>fine un campo <strong>de</strong> tipo precio.<br />

• AddFecha: <strong>de</strong>fine un campo <strong>de</strong> tipo fecha.<br />

• AddHora: <strong>de</strong>fine un campo <strong>de</strong> tipo hora.<br />

69


<strong>ControlsSAP</strong> Framework ®<br />

• AddLinkTable: <strong>de</strong>fine un campo alfanumérico <strong>de</strong> 8 caracteres, vinculado a una tabla <strong>de</strong><br />

usuario.<br />

• AddMemo: crea un campo <strong>de</strong> tipo texto.<br />

• AddNumerico: aña<strong>de</strong> un campo <strong>de</strong> tipo numérico <strong>de</strong> una longitud indicada.<br />

• AddPorcentaje: crea un campo <strong>de</strong> tipo porcentaje.<br />

Estas instrucciones <strong>de</strong>vuelven un objeto <strong>de</strong> tipo SAPUserField, que po<strong>de</strong>mos utilizar para añadir<br />

varios valores validos.<br />

11.1.2 Índices<br />

Des<strong>de</strong> el objeto SAPUserTable po<strong>de</strong>mos también <strong>de</strong>finir índices <strong>de</strong>s<strong>de</strong> la propiedad Keys.<br />

Po<strong>de</strong>mos <strong>de</strong>finir 2 tipos <strong>de</strong> índices:<br />

• AddIn<strong>de</strong>x: Aña<strong>de</strong> un índice a la tabla. Indicaremos el nombre <strong>de</strong>l índice y la lista <strong>de</strong><br />

campos que lo componen. Los campos se indicarán sin el ‘U_’.<br />

• AddUniqueIn<strong>de</strong>x: Aña<strong>de</strong> un índice como el anterior pero este <strong>de</strong> tipo único.<br />

11.2 Vistas<br />

Para crear vistas en la base <strong>de</strong> datos utilizaremos el objeto SAPView. Deberemos indicar el<br />

nombre <strong>de</strong> la vista y la consulta SQL.<br />

11.3 Procedimientos almacenados<br />

Para <strong>de</strong>finir procedimientos almacenados utilizaremos el objeto SAPProcedure. Indicaremos el<br />

nombre <strong>de</strong>l procedimiento a crear y la sentencia SQL que lo compone.<br />

11.4 Sentencia SQL<br />

Para realizar sentencias SQL como INSERT, UPDATE, DELETE, disponemos <strong>de</strong> método<br />

<strong>ControlsSAP</strong>.DoAction, que realiza la acción en el instante. Pero si lo que queremos es que se<br />

ejecuten este tipo <strong>de</strong> sentencias SQL en el momento <strong>de</strong> la carga <strong>de</strong> la aplicación, por ejemplo<br />

insertar valores por <strong>de</strong>fecto <strong>de</strong>spués <strong>de</strong> crear una tabla, entonces la sentencia anterior no nos<br />

serviría. Para esto existe el objeto SAPAction don<strong>de</strong> indicaremos la acción a realizar y la<br />

añadiremos junto con los <strong>de</strong>más objetos en el momento <strong>de</strong> crear.<br />

70


<strong>ControlsSAP</strong> Framework ®<br />

El objeto SAPAction no esta pensado para realizar acciones en la base <strong>de</strong> datos fuera <strong>de</strong> los<br />

formularios <strong>de</strong> tipo FormDLL (para añadirlos en el objeto Database). Para realizar este tipo<br />

acciones se <strong>de</strong>be utilizar la función <strong>ControlsSAP</strong>.DoAction.<br />

11.5 Categorías, consultas pre<strong>de</strong>finidas, búsquedas<br />

formateadas<br />

Po<strong>de</strong>mos añadir consultas pre<strong>de</strong>finidas, y búsquedas formateadas propias <strong>de</strong> SAP. Para ello<br />

<strong>de</strong>beremos añadir primero una categoría. Utilizaremos el objeto SAPQueryCategories<br />

indicando un nombre.<br />

La estructura <strong>de</strong> estos objetos en SAP es la siguiente:<br />

Categorías<br />

11.5.1 Consultas pre<strong>de</strong>finidas<br />

Des<strong>de</strong> el método AddQuery <strong>de</strong>l objeto SAPQueryCategories crearemos una consulta<br />

pre<strong>de</strong>finida <strong>de</strong> SAP <strong>de</strong> tipo SAPUserQuery. Deberemos indicarle un nombre a la consulta y la<br />

sentencia SQL a ejecutar.<br />

Podremos añadir al objeto SAPUserQuery búsquedas formateadas <strong>de</strong> SAP.<br />

11.5.2 Búsquedas formateadas<br />

Consultas pre<strong>de</strong>finidas<br />

Para añadir búsquedas formateadas propias <strong>de</strong> SAP Business One necesitaremos añadirlas<br />

<strong>de</strong>s<strong>de</strong> el objeto SAPUserQuery. Con el método AddFormatedSearch asignaremos estas<br />

búsquedas a las consultas <strong>de</strong> SAP.<br />

Dim q As New SAPQueryCategories(Me.Company, "Consultas Generales")<br />

With q<br />

With .AddQuery("ConsultaFamilias", _<br />

"SELECT Co<strong>de</strong>, Name FROM [@GSP_FAMILIES]<br />

WHERE U_GSP_GroupCo<strong>de</strong> = $[OITM.ItmsGrpCod]")<br />

.AddFormattedSearch("150", "U_GSP_FAMILIA")<br />

End With<br />

End With<br />

71<br />

Búsquedas formateadas

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!