Manual de programador _ControlsSAP.pdf
Manual de programador _ControlsSAP.pdf
Manual de programador _ControlsSAP.pdf
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