Statt in VB.NET eine eigene ActiveX Komponente zu implementieren, können Sie auch direkt eine Windows Form in das SAP GUI Fenster einbetten, indem Sie die Funktion guixt.EmbedForm() verwenden. In Verbindung mit einer zentralen Ablage der VB.NET dll, zum Beispiel in SAP Web Repository oder Mime Repository, ist dann auf den Benutzer-PCs keinerlei Installation oder Registrierung nötig. DIe VB.NET dll wird ja von GuiXT automatisch beim ersten Ansprechen in den GuiXT Cache geladen und dort ausgeführt. Wir zeigen das
in diesem Tutorial an dem Beispiel einer interaktiven Kundeninfo. Das
Beispiel ist relativ umfangreich, hat aber den Vorteil, eine Reihe von
Techniken zu enthalten, die für die Implementierung einer Anforderung
aus der Praxis hilfreich sind.
Die Form besteht aus mehreren Tabellen, Buttons und einem Diagramm. Für den Benutzer ist der Ablauf wie folgt:
Die Tabelle rechts oben zeigt die bisher verkauften Artikel, absteigend sortiert nach 5-Jahres-Umsatz. Durch Klick auf einen Artikel wird jeweils ein Umsatzdiagramm für den ausgewählten Artikel angezeigt:
Insgesamt ist die Implementierung zwischen VB.NET und GuiXT Scripten variabel aufgeteilt. Datenzugriffe und SAP-Aktionen sind in InputScripts realisiert, während die Benutzeroberfläche und das Erstellen der Diagramme in VB.NET erfolgt. Durch die Standard-.NET-Controls hat der Benutzer eine Reihe von Interaktionsmöglichkeiten -etwa nach Spalten zu sortieren -, die nicht separat implementiert werden müssen:
Das Einblenden der Kundeninfo kann im Prinzip in einer beliebigen Transaktion erfolgen. Wir haben hier den Weg beschritten, eine eigene Transaktion ZCSO anzulegen, der Einfachheit halber als Parametertransaktion zu einer bestehenden; der Transaktion START_REPORT, die für unser Beispiel genügt. Alle Scripte zum Herunterladen, einschließlich des VB.NET Projekts, finden Sie in zcso.zip. Bitte beachten Sie für eventuelle eigene Tests, dass wir das Erstellen der Diagramme über das (kostenlose) Microsoft-Zusatzpaket "MS Chart" implementiert haben, das nicht automatisch installiert ist. Sie finden in der zip-Datei zcso.zip auch die Installationsroutine zu MS Chart. Zum Öffnen des VB.NET Projekts bitte Visual Studio ab Version 2012 verwenden. Nach download der Datei zcso.zip ist meist ein "Unblock" nötig (rechte Maustaste -> Dateiattribute), sonst können die Dateien später nicht ausgeführt werden; oder "Unblock" nach Entpacken für die einzelnen Dateien.
GuiXT Script // ZCSO // delete existing elements (necessary if implemented as parameter
transaction) // initial screen? Title "Customer Sales Order Dashboard" InputField (1,1) "Customer" (1,20) size=10 name="zcso_kunnr_ext" techName="KNA1-KUNNR" -numerical On "Enter" process="zcso_init_enter.txt" Pushbutton (toolbar) "Start" "/0" "F8" process="zcso_init_enter.txt" else // titleTitle "&V[zcso_kunnr_ext]: &V[zcso_name1], &V[zcso_city], &V[zcso_country]" // area for VB.NET control. // We start at (-1,-1) and use a very large area in order to avoid any padding Control (-1,-1) (50,300) progID="Shell.Explorer" name="r1" initFlag="r1init"
// embed control
Pushbutton
(toolbar)
"Other customer"
process="zcso_main_back.txt"
On
"Enter"
process="zcso_main_enter.txt" endif
InputScipt zcso_init_enter.txt // customer number specified? if not V[zcso_kunnr_ext] return "E: Please specify a customer number" -statusline endif // customer number with 10 digits // set organization key values (option:read from user parameters) Set V[zcso_vtweg] "10" Set V[zcso_spart] "00" // prepare VB.NET form CallVB charts.zcso.initialize// read customer address include "zcso_read_address.txt" // read contacts include "zcso_read_contacts.txt" // read orders include "zcso_read_orders.txt" // read diagram data from S001 include "zcso_read_diagramdata.txt" // build tables, diagrams etc. // display main screen StatusMessage -removeReturn InputScipt zcso_read_address.txt // found? StatusMessage -remove return "E: Customer &V[zcso_kunnr_ext] not found" -statusline endif // read country text InputScipt zcso_read_contacts.txt // Build key table for function Set V[crwa] "" Set V[crwa](BAPICUSTOMER_IDRANGE-SIGN) "I" Set V[crwa](BAPICUSTOMER_IDRANGE-OPTION) "EQ" Set V[crwa](BAPICUSTOMER_IDRANGE-LOW) "&V[zcso_kunnr]" Set text[cr] "&V[crwa]" // clear result table // call function // transfer data to VB label contacts_lineCopyText fromText="contacts" toString="wa" line=&V[i] if Q[ok] Set V[zcso_contactname] "&V[wa](BAPICONTACT_ADDRESSDATA-LASTNAME), &V[wa](BAPICONTACT_ADDRESSDATA-FIRSTNAME)" Set V[zcso_contacttitle] "&V[wa](BAPICONTACT_ADDRESSDATA-FUNCTION)" Set V[zcso_contactphone] "&V[wa](BAPICONTACT_ADDRESSDATA-TEL1_NUMBR)" Set V[zcso_contactemail] "&V[wa](BAPICONTACT_ADDRESSDATA-E_MAIL)" CallVB charts.zcso.newcontact Set V[i] &V[i] + 1 goto contacts_line endif InputScipt zcso_read_orders.txt // read open orders // search condition Set V[condition] "&V[condition] and VTWEG = '&V[zcso_vtweg]' and SPART = '&V[zcso_spart]' and TRVOG = '0'" Set V[condition] "&V[condition] and AUDAT GE '&V[today-365_ymd]'" // clear result tables Set text[r2] "" Set text[r3] "" Set text[r4] "" Set text[r5] "" // read orders // pass to VB // clear result tables Set text[r2] "" Set text[r3] "" Set text[r4] "" Set text[r5] "" InputScipt zcso_read_diagramdata.txt // Determine years Set V[zcso_year0] &V[today_y] Set V[zcso_year1] &V[zcso_year0] - 1 Set V[zcso_year2] &V[zcso_year0] - 2 Set V[zcso_year3] &V[zcso_year0] - 3 Set V[zcso_year4] &V[zcso_year0] - 4 // search condition // Clear result tables Set text[r2] "" Set text[r3] "" // read VIS statistics table S001 // pass data to VB // Clear result tables Set text[r1] "" Set text[r2] "" Set text[r3] "" // obtain all product numbers from VB // read product names Set text[ctab] "" Set V[i] 1 label next CopyText fromText="zcso_products" toString="matnr" line="&V[i]" if Q[ok] if V[i=1] Set V[condline] "SPRAS = 'E' AND (MATNR = '&V[matnr]' else Set V[condline] "OR MATNR = '&V[matnr]'" endif CopyText fromString="condline" toText="ctab" -appendLine Set V[i] &V[i] + 1 goto next endif if V[i>1] Set V[condline] ")" CopyText fromString="condline" toText="ctab" -appendLine endif Call /guixt/select in.table="MAKT" in.fields="MATNR,MAKTX" table.conditiontable="ctab" table.V1table="r1" table.V2table="r2" endif // product names to VB
InputScipt zcso_create_order.txt Parameter PROMOTIONEnter "/nVA01" // Enter order type Set F[VBAK-AUART] "TA" Enter // Enter customer number Set F[KUAGV-KUNNR] "&V[zcso_kunnr]" if U[PROMOTION=1] Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-MABNR,1] "M-20" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-KWMENG,1] "1" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-MABNR,2] "PA-1000" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-KWMENG,2] "1" endif if U[PROMOTION=2] Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-MABNR,1] "M-20" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-KWMENG,1] "2" endif if U[PROMOTION=3] Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-MABNR,1] "PA-1000" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-KWMENG,1] "1" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-MABNR,2] "M-10" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-KWMENG,2] "1" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-MABNR,3] "P-103" Set cell[SAPMV45A_TCTRL_U_ERF_AUFTRAG,RV45A-KWMENG,3] "1" endif Enter // no delivery proposal? Enter "=WEIT" // no delivery proposal? Enter "=WEIT"
InputScipt zcso_display_order.txt if not V[zcso_vbeln]return "E: Please select an order" -statusline endif Enter "/nVA03"// Display order Set F[VBAK-VBELN] "&V[zcso_vbeln]" Enter // Skip Popup Enter InputScipt zcso_change_order.txt if not V[zcso_vbeln]return "E: Please select an order" -statusline endif Enter "/nVA02"// Display order Set F[VBAK-VBELN] "&V[zcso_vbeln]" Enter // Skip Popup Enter
InputScipt Zcso_display_customer.txt Enter "/nxd03"// Display customer Set F[RF02D-KUNNR] "&V[zcso_kunnr]" Set F[RF02D-VKORG] "&V[zcso_vkorg]" Set F[RF02D-VTWEG] "&V[zcso_vtweg]" Set F[RF02D-SPART] "&V[zcso_spart]" Enter InputScipt zcso_main_back.txt // back to initial screen Return
VB.NET Imports guinet Imports System.Windows.Forms Imports System.Data Imports System.Drawing Imports System.Windows.Forms.DataVisualization.Charting Public Class zcso #Region "Private data" ' interface to GuiXT Private myguixt As guixt ' Dictionary for sales per product and month Private matdict1 As New Dictionary(Of String, Decimal) ' Dictionary for sales per product Private matdict2 As New Dictionary(Of String, Decimal) ' Dictionary for product names Private matdict3 As New Dictionary(Of String, String) #End Region ' embed into SAP GUI window Public Sub embed(ByVal w As Object) guixt.EmbedForm(Me, w) End Sub ' initialize for new customer data Public Sub initialize() ' create guixt object for communication with GuiXT myguixt = New guixt ' clear data grids contacts.RowCount = 0 orders.RowCount = 0 matbuttons.RowCount = 0 ' clear product dictionaries matdict1.Clear() matdict2.Clear() matdict3.Clear() End Sub ' final display, all customer data are read Public Sub display() ' sort contacts contacts.Sort(contacts.Columns(0), _ System.ComponentModel.ListSortDirection.Ascending) ' sort orders orders.Sort(orders.Columns(0), _ System.ComponentModel.ListSortDirection.Descending) ' Build Sales chart GenerateSalesChart("*") ' no selection contacts.ClearSelection() orders.ClearSelection() End Sub ' Pass all product numbers to GuiXT via GuiXT long text variable Public Sub products_to_guixt() ' Pass product numbers back to GuiXT to obtain product names myguixt.SetText("zcso_products", String.Join(vbCrLf, matdict2.Keys)) End Sub ' Obtain all product texts from GuiXT via GuiXT long text variables Public Sub productnames_from_guixt() Dim products As String() = myguixt.GetText("r1").Split(vbCrLf) Dim productnames As String() = myguixt.GetText("r2").Split(vbCrLf) For k As Integer = 0 To products.Length - 1 matdict3.Add(products(k).Trim, productnames(k).Trim) Next End Sub #Region "Event handling" 'Create new standard order Private Sub buttoncreateorder_Click(sender As Object, _ e As EventArgs) _ Handles buttoncreateorder.Click myguixt.Input("OK:/0,process=zcso_create_order.txt") End Sub 'Create new order, promotion 1 Private Sub promotion1_Click(sender As Object, e As EventArgs) _ Handles promotion1.Click myguixt.Input("U[PROMOTION]:1;OK:/0,process=zcso_create_order.txt") End Sub 'Create new order, promotion 2 Private Sub promotion2_Click(sender As Object, e As EventArgs) _ Handles promotion2.Click myguixt.Input("U[PROMOTION]:2;OK:/0,process=zcso_create_order.txt") End Sub 'Create new order, promotion 3 Private Sub promotion3_Click(sender As Object, e As EventArgs) Handles promotion3.Click myguixt.Input("U[PROMOTION]:3;OK:/0,process=zcso_create_order.txt") End Sub ' Display customer order Private Sub buttondisplayyorder_Click(sender As Object, _ e As EventArgs) _ Handles buttondisplayorder.Click Dim ordernumber As String = "" For Each row In orders.SelectedRows ordernumber = row.Cells("ordervbeln").Value() Next myguixt.SetVariable("zcso_vbeln", ordernumber) myguixt.Input("OK:/0,process=zcso_display_order.txt") End Sub ' Change customer order Private Sub buttonchangeorder_Click(sender As Object, _ e As EventArgs) _ Handles buttonchangeorder.Click Dim ordernumber As String = "" For Each row In orders.SelectedRows ordernumber = row.Cells("ordervbeln").Value() Next myguixt.SetVariable("zcso_vbeln", ordernumber) myguixt.Input("OK:/0,process=zcso_change_order.txt") End Sub ' Click on product button to generate chart Private Sub matbuttons_CellClick(sender As Object, _ e As DataGridViewCellEventArgs) _ Handles matbuttons.CellClick Dim product As String = "" For Each row In matbuttons.SelectedRows product = row.Cells("prodnumber").Value() Next GenerateSalesChart(product) End Sub #End Region #Region "contacts" ' called from GuiXT for each new contact Public Sub newcontact() Dim k As Integer = contacts.Rows.Add() Dim c As System.Windows.Forms.DataGridViewCellCollection = _ contacts.Rows.Item(k).Cells c("contactname").Value = myguixt.GetVariable("zcso_contactname") c("contacttitle").Value = myguixt.GetVariable("zcso_contacttitle") c("contactphone").Value = myguixt.GetVariable("zcso_contactphone") c("contactemail").Value = myguixt.GetVariable("zcso_contactemail") End Sub #End Region #Region "orders" ' transfer order data from GuiXT to datagrid Public Sub neworders() Dim r1 As String() = myguixt.GetText("r1").Split(vbCrLf) Dim r2 As String() = myguixt.GetText("r2").Split(vbCrLf) Dim r3 As String() = myguixt.GetText("r3").Split(vbCrLf) Dim r4 As String() = myguixt.GetText("r4").Split(vbCrLf) Dim r5 As String() = myguixt.GetText("r5").Split(vbCrLf) For k As Integer = 0 To r1.Length - 1 orders.Rows.Add() Dim o As System.Windows.Forms.DataGridViewCellCollection = _ orders.Rows.Item(k).Cells o("ordervbeln").Value = CInt(r1(k).Trim) o("orderaudat").Value = r2(k).Trim o("orderauart").Value = r3(k).Trim o("ordernetwr").Value = Decimal.Parse(r4(k).Trim, _ Globalization.NumberStyles.AllowDecimalPoint).ToString() o("orderbstnk").Value = r5(k).Trim Next End Sub #End Region #Region "materials" Public Sub materialsales() Dim r1 As String() = myguixt.GetText("r1").Split(vbCrLf) Dim r2 As String() = myguixt.GetText("r2").Split(vbCrLf) Dim r3 As String() = myguixt.GetText("r3").Split(vbCrLf) For k As Integer = 0 To r1.Length - 1 Dim product As String = r1(k).Trim Dim year As String = r2(k).Trim.Substring(0, 4) Dim netwr As Decimal = Decimal.Parse(r3(k).Trim) Dim key As String = year & product If matdict1.ContainsKey(key) Then matdict1.Item(key) = matdict1.Item(key) + netwr Else matdict1.Add(key, netwr) End If ' product only If matdict2.ContainsKey(product) Then matdict2.Item(product) = matdict2.Item(product) + netwr Else matdict2.Add(product, netwr) End If Next End Sub #End Region #Region "charts" Private total_netwr0 As Decimal = 0 Private total_netwr1 As Decimal = 0 Private total_netwr2 As Decimal = 0 Private total_netwr3 As Decimal = 0 Private total_netwr4 As Decimal = 0 Public Sub GenerateSalesChart(product As String) ' create chart Dim Chart1 As New Chart() Chart1.Size = New System.Drawing.Size(salesdiagram.Size.Width, _ salesdiagram.Size.Height) Chart1.BackColor = Color.FromArgb(240, 240, 240) Dim ChartArea1 As New ChartArea ChartArea1.Name = "ChartArea1" Chart1.ChartAreas.Add(ChartArea1) Dim Series1 As New Series Series1.ChartArea = "ChartArea1" Series1.Palette = ChartColorPalette.Pastel Series1.XValueMember = "Year" Series1.YValueMembers = "Sales" Chart1.Series.Add(Series1) Dim table As New DataTable ' Create columns in the DataTable table.Columns.Add("Year", GetType(String)) table.Columns.Add("Sales", GetType(Integer)) Dim year0 As String = myguixt.GetVariable("zcso_year0") Dim year1 As String = myguixt.GetVariable("zcso_year1") Dim year2 As String = myguixt.GetVariable("zcso_year2") Dim year3 As String = myguixt.GetVariable("zcso_year3") Dim year4 As String = myguixt.GetVariable("zcso_year4") Dim netwr0 As Decimal = 0 Dim netwr1 As Decimal = 0 Dim netwr2 As Decimal = 0 Dim netwr3 As Decimal = 0 Dim netwr4 As Decimal = 0 For Each m In matdict1 If product = "*" Or product = "***" _ Or product = m.Key.Substring(4) Then Select Case m.Key.Substring(0, 4) Case year0 netwr0 += m.Value Case year1 netwr1 += m.Value Case year2 netwr2 += m.Value Case year3 netwr3 += m.Value Case year4 netwr4 += m.Value End Select End If Next ' Save total values If product = "*" Then total_netwr0 = netwr0 total_netwr1 = netwr1 total_netwr2 = netwr2 total_netwr3 = netwr3 total_netwr4 = netwr4 ' build matbuttons Dim total_netwr As Decimal = total_netwr0 + total_netwr1 _ + total_netwr2 + total_netwr3 + total_netwr4 matbuttons.Rows.Add() Dim mb As System.Windows.Forms.DataGridViewCellCollection = _ matbuttons.Rows.Item(0).Cells mb("percentage").Value = "100" mb("product").Value = "***" mb("prodnumber").Value = "***" mb("prodname").Value = "All products" mb("netwr").Value = total_netwr ' select first row matbuttons.ClearSelection() matbuttons.Rows.Item(0).Selected = True For Each m In matdict2 Dim k As Integer = matbuttons.Rows.Add() mb = matbuttons.Rows.Item(k).Cells Dim percentage As Integer ' avoid to divide by 0 If total_netwr = 0 Then percentage = 0 Else percentage = CInt(m.Value * 100 / total_netwr) End If mb("percentage").Value = percentage.ToString ' Suppress leading 000 If IsNumeric(m.Key) Then mb("product").Value = CInt(m.Key).ToString Else mb("product").Value = m.Key End If mb("prodnumber").Value = m.Key mb("prodname").Value = matdict3.Item(m.Key) mb("netwr").Value = m.Value Next ' sortmatbuttons matbuttons.Sort(matbuttons.Columns("netwr"), _ System.ComponentModel.ListSortDirection.Descending) End If ' Sales figures for 5 years table.Rows.Add(year4, CInt(netwr4)) table.Rows.Add(year3, CInt(netwr3)) table.Rows.Add(year2, CInt(netwr2)) table.Rows.Add(year1, CInt(netwr1)) table.Rows.Add(year0, CInt(netwr0)) ' Chart data Chart1.DataSource = table Dim bmp As New Bitmap(Chart1.Width, Chart1.Height) Dim rec As New Rectangle(0, 0, Chart1.Width, Chart1.Height) Chart1.DrawToBitmap(bmp, rec) salesdiagram.Image = bmp ' Title variable If product = "*" OrElse product = "***" Then product_selected.Text = "All products" Else product_selected.Text = product & " " & matdict3.Item(product) End If salesdiagram.Refresh() End Sub #End Region End Class |