Bestehende Rechnung kopieren

Manchmal will man eine bestehende Rechnung duplizieren. Dabei kann man Originalcode, etwas angepasst, verwenden:

Public Sub cstm_CopyRechnung()
' Original: Die Verkaufschance wird mit allen Positionen kopiert
Dim tblRechnung As OrgDbServer31.Table

On Error GoTo ErrHandler

Set tblRechnung = Database.Tables("Rechnungen")
If tblRechnung.EOF Then Exit Sub

If MsgBox("Möchten Sie die aktuelle Rechnung mit allen Positionen kopieren?", _
vbQuestion + vbYesNo, MsgBoxTitle) = vbNo Then Exit Sub

With New CInvoicing
Set .mtblInvoices = tblRechnung
Set .mtblPositions = gTables.GetTable(dbtblRechnungspositionen)
.CopyInvoice
End With

Exit Sub

ErrHandler:
gErrors.DisplayError csErrSource & ".cstm_CopyRechnung"
End Sub

Wie fange ich mit der orgAnice-Programmierung an? (1)

Ich will hier keine VBA-Programmierung schulen. Etwas Grundkenntnisse setze ich voraus. Es gibt genug Tutorials im Internet hierzu. Microsoft hat zwar VB6 (Visual Basic for Applications) schon vor Jahren abgekündigt und will nur sein Visual Studio sehen, das „Problem“ ist aber, das in allen Office-Produkten noch VBA vertreten ist. Daher ist ein Austausch nicht einfach möglich, da es viele Anwender gibt, welche kleinere und größere Programmierungen durchgeführt hat. Wer schon einmal versucht hat, ein bestehendes VB-Projekt nach Visual-Studio zu importieren, weiss, welche Probleme auftreten können. Wir können also bestimmt noch ein paar Jahre auf VBA vertrauen. Und, kann man ein VBA, kann man auch andere Office-Produkte programmieren.

Also, wo fängt man an? Am besten bei den sogenannten „Basics“ (Grundlagen). VBA besteht aus Formularen, Modulen und Klassen. Dabei sind zwei Module zu beachten. Im Modul „Macros“ stehen die Aufrufe der orgAnice-Original-Macros. Im Modul „Usermacros“ die Aufrufe von Addons und sonstige Macros. Hier gehören auch unsere Aufrufe hinein. Die Prozeduren beider Module stehen dann in orgAnice für die Buttons zur Verfügung.

Die eigentlichen Macros sollten dann in eigenen customized Modulen stehen. Das macht das spätere Update einfacher. Was customizen ist und was dort zu beachten ist, steht in einem anderen Beitrag.

Fangen wir für den Anfang einmal einfach an (Hello World). Wir definieren ein eigenes Modul „cstm2_macros“. Hier erstellen wir eine einfache Prozedur:

Public Sub cstm2_HelloWorld()
    msgbox "Hello World"
end Sub

Diese könnten wir jetzt sofort starten. Dafür gibt es den Play-Button oben in der Symbolleiste. Aber wir wollen orgAnice-konform bleiben. Daher erstellen wir eine Prozedur in UserMacros:

Public Sub cstm2_Start()
    cstm2_macros.cstm2_HelloWorld
end Sub

Diese Prozedur könnten wir uns jetzt auch auf einen Button in orgData, der Oberfläche von orgAnice legen und dort starten. Ein Modul, zwei Prozeduren und schon der erste Erfolg. Das war zum warm werden. Im folgenden wollen wir uns dann um schönere Dinge kümmern.

Kurzer Abschweif. Wo liegen die Probleme bei der Programmierung von orgAnice. Man kennt das Objektmodell nicht. Das ist aber bei allen Anfängen das gleiche. Was macht man? Als Profi sieht man sich das Objektmodell mit <F2> im Objektexplorer an, als Anfänger sieht man sich einfach die DEMO-Datenbank an. Ca. 90% alle Befehle werden dort verwendet und davon sind ca. 90% auch kommentiert. Das sollte für den Anfang auch reichen. Man sucht sich einfach den gewünschten Befehl und sieht sich an, wie andere damit umgegangen sind. Wie sucht man? Natürlich mit <Strg><f>, genauso wie in orgAnice, allen Office-Produkten, sowie vielen anderen Produkten.

 

OKB-000239 | Objekterstellung durch ActiveX-Komponente nicht möglich

FAQ-Nr: OKB-000239


Betrifft:
orgAnice Designer (alle Versionen)


Problem:

Beim Starten des Designers (egal ob mit Administratorrechten oder ohne) erscheint die Fehlermeldung:

orgAnice Datenbank-Designer
„Objekterstellung durch ActiveX-Komponente nicht möglich (&HH1AD)“

okb-000239_001

Oder

orgAnice Datenbank-Designer
„ActiveX component can’t create object (&H1AD)“

okb-000239_002

Ursache:
Fehlerhafte Lizenzdateien


Lösung:

Löschen Sie die Lizenzdateien. Je nach Version des orgAnice Designers befinden Sie diese an unterschiedlichen Orten:

– Installationsverzeichnis des orgAnice Designers
„C:\Users\<Ihr BenutzerName>\AppData\Roaming\orgAnice Software GmbH\“

Löschen Sie jeweils die *.lic-Dateien. Nach dem Start des orgAnice Designers geben Sie Ihre Lizenzdaten neu ein und das Programm startet.

OKB-000244 | Verwendung von kaskadierenden Lookup-Tabellen

Betrifft: ab orgAnice CRM 2008

 

Frage: 

Was ist bei der Einrichtung von kaskadierenden Lookup-Tabellen zu beachten?

Antwort: 

– Die Controls müssen alle im gleichen Tabellenlayout sein !

– Das steuernde Control muss in der Liste der FormControls oberhalb stehen !

– Das steuernde Control darf keine editierbare Lookupliste sein !

– Das gesteuerte Control kann eine editierbare Lookupliste sein

OKB-000270 | Datensätze mit bestimmten Dokumenten markieren

Betrifft: ab orgAnice CRM 2008

Frage:

Wie kann man Datensätze markieren, die ein Dokument eines bestimmten Typs beinhalten? Z.B. alle Aktivitäten, die ein Word-Dokument beinhalten?

Lösung:

Es ist nicht möglich die Aufgabenstellung mit dem Markierungs-Assistenten zu lösen, da es innerhalb von orgBasic keine Möglichkeit gibt auf den Dokumententyp bzw. die Dateiendung zuzugreifen. Wir müssen ein VBA-Makro zu Hilfe ziehen:

Sub MarkDoc()
' Markiert in der Tabelle Aktivitäten alle Datensätze,
' die ein Word-Dokument (mit der Endung .doc) beinhalten
Dim tbl As OrgDbServer31.Table
Dim doc As OrgDbServer31.Document

Set tbl = Database.Tables("Aktivitaeten")

With tbl
	.Indexes.SetActiveIndex "ID"
	.UnmarkAll
	.GoTop
	Do While Not .EOF
		Set doc = tbl.Fields("Dokument").value
		If Not doc Is Nothing Then
			If doc.DefaultExtension = ".doc" Then
				.SetMark True
			End If
		End If
		.Skip
	Loop
End With

End Sub

In bestimmten Fällen kann es gewünscht sein, Dokumente eine bestimmten Typs als externe Dokumente abzulegen. Hier eine erweiterte Version der obigen Prozedur, die die gefundenen Dokumente als externe Dokumente ablegt:

Sub MoveDocTypeToExtern(psType As String, psTableName As String, psPath As String, psFileName As String)
' übergebenen Dokumenttyp von intern nach extern.
' psPath mit abschliessendem "\" angeben!
' Der in psPath angegebene Pfad muss existieren
Dim tbl As OrgDbServer31.Table
Dim doc As OrgDbServer31.Document
Dim sPath As String

On Error GoTo ErrHandler

Set tbl = Database.Tables(psTableName)
With tbl
	.Indexes.SetActiveIndex "ID", ORGDB_NAV_NOEVENTS
	.UnmarkAll ORGDB_NAV_NOEVENTS
	.GoTop ORGDB_NAV_NOEVENTS + ORGDB_NAV_NORELATIONS
	Do While Not .EOF
		Set doc = tbl.Fields("Dokument").value
		If Not doc Is Nothing Then
			If doc.DefaultExtension = psType Then
				.SetMark True
				sPath = psPath &amp; psFileName &amp; " " &amp; .Fields("ID").value &amp; doc.DefaultExtension
				doc.SaveAs sPath
				Set doc = Database.Documents.CreateLink(sPath)
				tbl.Fields("Dokument").value = doc
				.Write
			End If
		End If
		.Skip 1, ORGDB_NAV_NOEVENTS + ORGDB_NAV_NORELATIONS
	Loop
End With

Exit Sub

ErrHandler:
gErrors.DisplayError Hex(Err.Number) &amp; ", " &amp; Err.Description &amp; ", MoveDocTypeToExtern, Tabelle: " &amp; psTableName &amp; ", ID: " &amp; tbl.Fields("ID").value

End Sub

Beispielaufruf:

MoveDocTypeToExtern „.doc“, „Aktivitaeten“, „D:\Test\“, „AktivitaetenID“

Vielen Dank an Herrn Kopplin von K+K Software E. + K. Kopplin GbR, dem Hersteller von KKMandant, für die Zurverfügungstellung des Quellcodes.

OKB-000269 | Kaufmännisches Runden in orgBasic

Betrifft: ab orgAnice CRM 2008

Frage:

Wie runde ich kaufmännische in orgBasic?

Lösung:

Function Runden(pdblWert As Double, plNachkommastellen As Long) As Double

‚ Rundet eine Zahl auf eine bestimme Anzahl von Nachkommastellen.

‚ Ab 5 wird aufgerundet.

Dim sZahl As String

Dim lKommaPosition As Long

Dim bAufrunden As Boolean

Dim sNachkommastellen As String

‚ Zahl in Zeichenkette umwandeln. Drei Zeichen zusätzlich

‚ als Nachkommastellen reservieren, um die Rundung zu umgehen

sZahl = Trim(Str(pdblWert, 50, plNachkommastellen + 3))

‚ Wir runden auf, wenn die drittletzte Stelle >= 5 ist

bAufrunden = Left(Right(sZahl, 3), 1) >= „5“

‚ Alle zusätzlichen Stellen können jetzt abgeschnitten werden

sZahl = Left(sZahl, Len(sZahl) – 3)

If bAufrunden Then

‚ Dezimaltrennzeichenposition bestimmen

lKommaPosition = Len(sZahl) – InStr(sZahl, „.“)

‚ Dezimaltrennzeichen ausschneiden

sZahl = Left(sZahl, Len(sZahl) – lKommaPosition – 1) & Right(sZahl, lKommaPosition)

‚ Wert um 1 erhöhen

sZahl = Trim(Str(Val(sZahl) + 1, Len(sZahl) + 1, 0))

‚ Dezimaltrennzeichen wieder einfügen

sNachkommastellen = Right(sZahl, lKommaPosition)

sZahl = Left(sZahl, Len(sZahl) – Len(sNachkommastellen)) & „.“ & sNachkommastellen

End If

Runden = Val(sZahl)

End Function

Oder

Function Runden(pdblWert As Double, plNachkommastellen As Long) As Double

‚ Rundet eine Zahl auf eine bestimme Anzahl von Nachkommastellen.

‚ Ab 5 wird aufgerundet.

Runden = Lng(pdblWert * 10 ^ plNachkommastellen + 0.5) / 10 ^ plNachkommastellen

End Function

OKB-000256 | Alle unbenannten Steuerelemente benennen

Betrifft: ab orgAnice 2008

Frage: Wie kann ich im VBA alle in einem Tabellenlayout vorhandene Steuerelemente benennen?

Lösung:

Public Sub NameAllControls()

' Benennt alle unbenannten Controls in den Tabellenlayouts
Dim i As Long
Dim k As Long
Dim l As Long: l = 0
Dim m As Long

On Error Resume Next

' Alle Tabellenlayouts durchgehen

For i = 0 To Application.TableLayouts.count - 1
	With Application.TableLayouts(i)
		Debug.Print "TableLayout " &amp; .Name
   		' Alle Steuerelemente durchgehen
   		For k = 0 To .FormControls.count - 1
      			With .FormControls(k)
      			' Wenn das Steuerelement unbenannt ist, dann Nach Typ entsprechend benennen
         			If Trim(.Name) = "" Then
            				.Name = NameControl(.Type, l)
            				Debug.Print " Control named " &amp; .Name
            				l = l + 1
         			End If
         			' Unterelemente von Registern durchgehen
         			If .Type = ORGDATA_CONTROL_TABSTRIP Then
            				For m = 0 To .SubForms.count - 1
              					With .SubForms(m)
               						' Wenn das Steuerelement unbenannt ist, dann Nach Typ entsprechend benennen
                  					If Trim(.Name) = "" Then
                     						.Name = NameControl(.Type, l)
                     						Debug.Print " Control named " &amp; .Name
                     						l = l + 1
                  					End If
               					End With
            				Next m
         			End If
      			End With
		Next k
	End With
	Debug.Print ""
Next i
End Sub

Private Function NameControl(psType As OrgDataControlTypesEnum, plNumber As Long) As String
' Benennt ein einzelnes Steuerelement
Const csStaticText = "txt"
Const csLabel = "lbl"
Const csLabel3D = "lbl"
Const csDynamicText = "txt"
Const csFrame = "fra"
Const csTextBox = "txt"
Const csMultiLineTextBox = "txt"
Const csPopUpTextBox = "txt"
Const csEuro = "eur"
Const csCheckBox = "chk"
Const csDate = "dtp"
Const csTime = "dtp"
Const csDateAndTime = "dtp"
Const csLookUpList = "cbo"
Const csLookUpEdit = "cbo"
Const csLookUpUsers = "cbo"
Const csRadioButtons = "opt"
Const csDocument = "doc"
Const csCommandButton = "cmd"
Const csActiveX = "act"
Const csTabStrip = "tab"
Const csLookUpPermissions = "cbo"

On Error GoTo ErrHandler

Select Case psType
	Case ORGDATA_CONTROL_STATICTEXT
		NameControl = csStaticText &amp; plNumber
	Case ORGDATA_CONTROL_LABEL
		NameControl = csLabel &amp; plNumber
	Case ORGDATA_CONTROL_LABEL3D
		NameControl = csLabel3D &amp; plNumber
	Case ORGDATA_CONTROL_DYNAMICTEXT
		NameControl = csDynamicText &amp; plNumber
	Case ORGDATA_CONTROL_FRAME
		NameControl = csFrame &amp; plNumber
	Case ORGDATA_CONTROL_TEXTBOX
		NameControl = csTextBox &amp; plNumber
	Case ORGDATA_CONTROL_MULTILINETEXTBOX
		NameControl = csMultiLineTextBox &amp; plNumber
	Case ORGDATA_CONTROL_POPUPTEXTBOX
		NameControl = csPopUpTextBox &amp; plNumber
	Case ORGDATA_CONTROL_EURO
		NameControl = csEuro &amp; plNumber
	Case ORGDATA_CONTROL_CHECKBOX
		NameControl = csCheckBox &amp; plNumber
	Case ORGDATA_CONTROL_DATE
		NameControl = csDate &amp; plNumber
	Case ORGDATA_CONTROL_TIME
		NameControl = csTime &amp; plNumber
	Case ORGDATA_CONTROL_DATEANDTIME
		NameControl = csDateAndTime &amp; plNumber
	Case ORGDATA_CONTROL_LOOKUPLIST
		NameControl = csLookUpList &amp; plNumber
	Case ORGDATA_CONTROL_LOOKUPEDIT
		NameControl = csLookUpEdit &amp; plNumber
	Case ORGDATA_CONTROL_LOOKUPUSERS
		NameControl = csLookUpUsers &amp; plNumber
	Case ORGDATA_CONTROL_RADIOBUTTONS
		NameControl = csRadioButtons &amp; plNumber
	Case ORGDATA_CONTROL_DOCUMENT
		NameControl = csDocument &amp; plNumber
	Case ORGDATA_CONTROL_COMMANDBUTTON
		NameControl = csCommandButton &amp; plNumber
	Case ORGDATA_CONTROL_ACTIVEX
		NameControl = csActiveX &amp; plNumber
	Case ORGDATA_CONTROL_TABSTRIP
		NameControl = csTabStrip &amp; plNumber
	Case ORGDATA_CONTROL_LOOKUPPERMISSIONS
		NameControl = csLookUpPermissions &amp; plNumber
End Select
Exit Function
ErrHandler:
Err.Raise Err.Number, csErrSource &amp; "NameControl"
End Function

OKB-000258 | Auswerten von orgBasic-Ausdrücken

Betrifft: ab orgAnice 3

Frage: 

Kann man aus dem VBA auf orgBasis-Ausdrücke (persistente Variablen, angepasste Funktionen, Kernfunktionen, Tabellenfelder) zugreifen?

Lösung: 

Ja, kann man, das geschieht mit Hilfe des ParserRequest-Objekts.

Hinweis: Der Zugriff aus angepassten Funktionen auf den VBA-Code ist nicht möglich.

Beispiel:

Public Sub ParserRequestExample()

    ‚ Demonstriert die Verwendung von ParserRequests:

    ‚ den Zugriff auf Felder, angepasste Funktionen,

    ‚ Kernfunktionen und persistente Variablen

    Dim prq As ParserRequest

    Dim sReturn As String

    ‚ Feldzugriff

    Set prq = Database.Parser.CreateRequest(„Adressen->Name“)

    sReturn = prq.Evaluate

    Debug.Print sReturn

    ‚ Angepasste Funktion

    Set prq = Database.Parser.CreateRequest(„Name()“)

    sReturn = prq.Evaluate

    Debug.Print sReturn

    ‚ Kernfunktion

    Set prq = Database.Parser.CreateRequest(„CurrentUser()“)

    sReturn = prq.Evaluate

    Debug.Print sReturn

    ‚ Persistente Variable

    Set prq = Database.Parser.CreateRequest(„g_Land“)

    sReturn = prq.Evaluate

    Debug.Print sReturn

    ‚ Kombination mehrerer Möglichkeiten

    Set prq = Database.Parser.CreateRequest(„““Hallo „“ & Name() & „“ aus „“ & Adressen->Ort“)

    sReturn = prq.Evaluate

    Debug.Print sReturn

End Sub

OKB-000243 | Reagieren auf Arbeitsbereichswechsel

Betrifft: ab orgAnice Pi

Frage: 

Über welches OrgDataEvent / Command habe ich Zugriff auf den Wechsel des Arbeitsbereichs oder der Arbeitsbereichsgruppe?

Antwort: 

Zunächst muss man sagen, dass es weder einen Event noch einen CommandID-Parameter für den Wechsel von Arbeitsbereichen oder Arbeitsbereichsgruppen gibt. Denn es gibt nur CommandID-Parameter für fest in orgAnice eingebaute Befehle und Arbeitsbereiche bzw. Arbeitsbereichsgruppen gehören nicht dazu.

Allerdings gibt es doch einen Lösungsansatz: Beim Wechsel von Arbeitsbereichen oder Arbeitsbereichsgruppen wird mehrmals das Event „CommandAvailable“ abgefeuert. Hier setzen wir an und vergleichen, ob sich seit dem letzten Aufruf der aktive Arbeitsbereich geändert hat. Wenn das der Fall ist, setzen wir bspw. eine bestimmte Tabelle als aktiv und merken uns den Arbeitsbereich, damit beim erneuten Aufruf von CommandAvailable nicht wieder die Tabelle als aktiv gesetzt wird. Der Code, der in der Prozedur COrgDataEvents.mOrgData_CommandAvailable hinzugefügt werden muss (am besten ganz unten vor dem Exit Sub), sieht folgendermaßen aus:

' Wurde der Arbeitsbereich geändert?

    If Not wsLastActiveWorkspace Is Workspaces.ActiveWorkspace Then

        Set wsLastActiveWorkspace = Workspaces.ActiveWorkspace

        ' Je Arbeitsbereich eine bestimmte Tabelle aktivieren

        Select Case Workspaces.ActiveWorkspace.Name

            Case "Vorgaenge" ' Vorgänge und Aktivitäten

                ActiveTable = gTables.GetTable(dbtblAktivitäten)

            Case "Adressen" ' Adressmerkmale

                ActiveTable = gTables.GetTable(dbtblAdressmerkmale)

        End Select

    End If

Wir müssen nur noch im Deklarationsteil der Prozedur eine neue statische Variable deklarieren:

Static wsLastActiveWorkspace As Workspace

Das war es! In dem o.a. Beispiel wird beim Wechsel in den Arbeitsbereich „Vorgänge und Aktivitäten“ die Aktivitäten-Tabelle, beim Wechsel den Arbeitsbereich „Adressmerkmale“ die Adressmerkmale-Tabelle aktiviert. Natürlich können an dieser Stelle auch weitere Aktionen und eigene Prozeduren ausgeführt werden.

Für den Einsatz in einer Datenbank sollte natürlich eine eigene CSTM_COrgDataEvents-Klasse erstellt werden.

OKB-000245 | Beschreibung der COM-Schnittstelle

Betrifft: ab orgAnice Pi

Frage: 

Wo finde ich eine Dokumentation der COM-Schnittstelle von orgAnice?

Lösung: 

Die Beschreibung der COM-Schnittstelle von orgAnice finden Sie an den folgenden Stellen:

1.) Die Hilfedatei zu der COM-Schnittstelle des orgAnice Database Servers (orgDbServer31) OrgDbServer.chm im Unterordner „Server“ des orgAnice-Ordners (standardmäßig „C:\Programme\orgAnice Software\orgAnice X.X\Server“)

2.) Zu jeder COM-Methode der Hauptkomponenten von orgAnice, orgAnice Database Server und orgAnice Data, finden Sie in dem Objektkatalog von VB/VBA (aufrufbar über F2) eine Beschreibung:

3.) Die beste Quelle für Informationen, wie eine Methode der COM-Schnittstelle der orgAnice-Komponenten verwendet wird, bieten die Makros in der Standard-CRM-Datenbank. Dort wird fast jede Methode verwendet, meistens finden Sie auch Kommentare, die die Funktionsweise erklären.