Load Accounting Trade via Excel - Implementation Details
The main method 'LoadData' is called on clicking SUBMIT button. It initiates construction of the XML document and the loading process:
Sub LoadData()
Dim ServerURL As String
Dim Login As String
Dim Pass As String
Dim composedObject As String
ServerURL = Range("B5").Text
Login = Range("B6").Text
Pass = ActiveSheet.TextBox1.Text
composedObject = ComposeXML().XML
If Login <> "" And Pass <> "" Then
LoadAndRetrieveTSR ServerURL, Login, Pass, composedObject
Else
MsgBox "Invalid authorization!"
End If
End Sub
It calls the 'ComposeXML' function to compose an XML document, based on the filled fields of the AccountingTrade objects:
'Composes an XML documents based on the non-empty fields of the hierarchal representation of the AccountingTrade object
Function ComposeXML() As MSXML2.DOMDocument
'A document to compose
Dim document As MSXML2.DOMDocument
Set document = New MSXML2.DOMDocument
Dim mainNode As MSXML2.IXMLDOMNode
Set mainNode = document.createElement("accountingTrade")
document.appendChild mainNode
'Add identifiers
Dim tempNode As MSXML2.IXMLDOMNode
Set tempNode = document.createElement("objectType")
tempNode.appendChild document.createTextNode("AccountingTrade")
mainNode.appendChild tempNode
Set tempNode = document.createElement("objectId")
tempNode.appendChild document.createTextNode("AccountingTrade")
mainNode.appendChild tempNode
Set tempNode = document.createElement("objectDescription")
tempNode.appendChild document.createTextNode("ACCOUNTING")
mainNode.appendChild tempNode
Dim mainSheet As Object
Set mainSheet = ActiveWorkbook.Sheets(1)
Dim lastFilterRow As Long
lastFilterRow = mainSheet.Cells(Rows.Count, 1).End(xlUp).Row
Dim curPath As String
curPath = ""
Dim i As Integer
For i = 15 To lastFilterRow - 1
Dim curName As String
curName = mainSheet.Cells(i, 1)
If StrComp(Mid(curName, 1, 2), "</", vbTextCompare) = 0 Then
curPath = Mid(curPath, 1, InStrRev(curPath, "/", -1, vbTextCompare) - 1)
Else
If StrComp(Mid(curName, 1, 1), "<", vbTextCompare) = 0 Then
curPath = curPath & "/" & Mid(curName, 2, Len(curName) - 2)
Else
If Len(curName) > 0 And Len(mainSheet.Cells(i, 2)) > 0 Then
Dim curValue As String
curValue = mainSheet.Cells(i, 2)
InsertNodeIntoDocument document, curPath & "/" & curName, curValue
End If
End If
End If
Next i
Set ComposeXML = document
End Function
Each created node is inserted using its path from document's root, a name and a value, if the value is not empty, by means of the 'InsertNodeIntoDocument' method:
Sub InsertNodeIntoDocument(doc As MSXML2.DOMDocument, path As String, value As String)
Dim PathParts() As String
PathParts = Split(path, "/", -1, vbTextCompare)
Dim curPos As MSXML2.IXMLDOMElement
Set curPos = doc.FirstChild
Dim i As Integer
Dim lastElemInd As Integer
lastElemInd = UBound(PathParts)
For i = 1 To lastElemInd - 1
Dim list As collection
Set list = getImmediateChildrenByName(curPos, PathParts(i))
If list.Count > 0 Then
Set curPos = list.Item(1)
Else
Dim newNode As MSXML2.IXMLDOMElement
Set newNode = doc.createElement(PathParts(i))
curPos.appendChild newNode
Set curPos = newNode
End If
Next i
Set newNode = doc.createElement(PathParts(lastElemInd))
curPos.appendChild newNode
Set curPos = newNode
Dim valueNode As MSXML2.IXMLDOMText
Set valueNode = doc.createTextNode(value)
curPos.appendChild valueNode
End Sub
'getImmediateChildrenByName' function is used to get immediate child nodes of the specified node, with a specified name:
Function getImmediateChildrenByName(elem As MSXML2.IXMLDOMElement, name As String) As collection
Dim res As collection
Set res = New collection
Dim list As MSXML2.IXMLDOMNodeList
Set list = elem.ChildNodes
Dim length As Integer
length = list.length
Dim i As Integer
For i = 0 To length - 1
If list.Item(i).NodeType = NODE_ELEMENT And StrComp(list.Item(i).nodeName, name, vbTextCompare) = 0 Then
res.Add list.Item(i)
End If
Next i
Set getImmediateChildrenByName = res
End Function
After an XML document is composed, the 'LoadAndRetrieveTSR' method is called to initiate loading process and to retrieve the TSR:
Sub LoadAndRetrieveTSR(url As String, Login As String, Pass As String, composedObject As String)
Dim sEnv As String
Dim sRTR As String
sRTR = "<EagleML xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:type=""LoadAccounting"" eaglemlVersion=""2-0"" actualBuild=""1"" xmlns=""http://www.eagleinvsys.com/2011/EagleML-2-0"">"
sRTR = sRTR & "<header xmlns=""http://www.eagleinvsys.com/2011/EagleML-2-0"">"
sRTR = sRTR & "<messageId>" & Format(Now(), "yyyymmddThhmmss") & "</messageId>"
sRTR = sRTR & "<sentBy>http://client.com</sentBy>"
sRTR = sRTR & "<sendTo>http://www.eagleinvsys.com/eagle_ml-2-0_default_cm_control_message</sendTo>"
sRTR = sRTR & "</header>"
sRTR = sRTR & "<taskIdentifier>"
sRTR = sRTR & "<correlationId>" & Format(Now(), "yyyymmddThhmmss") & "</correlationId>"
sRTR = sRTR & "<businessTaskId>LoadAccountingTrade</businessTaskId>"
sRTR = sRTR & "</taskIdentifier>"
sRTR = sRTR & "<taskTypeEnum>LOAD</taskTypeEnum>"
sRTR = sRTR & "<synchronousExecution>yes</synchronousExecution>"
sRTR = sRTR & "<accountingTransaction>"
sRTR = sRTR & composedObject
sRTR = sRTR & "</accountingTransaction>"
sRTR = sRTR & "</EagleML>"
sEnv = "<?xml version=""1.0"" encoding=""utf-8""?>"
sEnv = sEnv & "<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">"
sEnv = sEnv & " <s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">"
sEnv = sEnv & " <accountingTransactionMessage>"
sEnv = sEnv & sRTR
sEnv = sEnv & " </accountingTransactionMessage>"
sEnv = sEnv & " </s:Body>"
sEnv = sEnv & "</s:Envelope>"
ContinueLoad sEnv, url, Login, Pass
End Sub
This method creates a SOAP message to initiate a load task of an AccountingTrade object, which is then sent to the web service of the specified region by the 'ContinueLoad' method:
Sub ContinueLoad(data As String, url As String, Login As String, Pass As String)
Dim StrXML As String
Dim DirPathToXML As String
Dim xmlHtp As Object
Set xmlHtp = CreateObject("Microsoft.XmlHttp")
Dim xDoc As MSXML2.DOMDocument
Set xDoc = New MSXML2.DOMDocument
DirPathToXML = CurDir() & "\tsr.xml"
With xmlHtp
.Open "POST", url & "/EagleMLWebService20", False, Login, Pass
.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
.setRequestHeader "Host", Replace(Replace(url, "http://", ""), "https://", "")
.setRequestHeader "Content-Encoding", "gzip, deflate"
.setRequestHeader "soapAction", "/EagleMLWebService/LoadAccounting"
.send "" & data
xDoc.LoadXML .responseText
End With
Shell "cmd.exe /c cd. > " & DirPathToXML
Open DirPathToXML For Output As #1
Print #1, xDoc.XML
Reset
ImportXMLToList DirPathToXML
Set xmlHtp = Nothing
Set xDoc = Nothing
End Sub
This method sends a composed SOAP message to the web service and retrieves the TSR message, which is then imported to the table representation and is added to the TSR sheet of the workbook by the 'ImportXMLToList' method:
Sub ImportXMLtoList(PathToXML As String)
Dim wb As Workbook
Dim currentBook As Workbook
Set currentBook = ActiveWorkbook
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set wb = Workbooks.OpenXML(Filename:=PathToXML, LoadOption:=xlXmlLoadImportToList)
Application.DisplayAlerts = True
Dim tsrSheet As Object
On Error Resume Next
Set tsrSheet = currentBook.Sheets("TSR")
If tsrSheet Is Nothing Then
Set tsrSheet = currentBook.Sheets.Add(After:=currentBook.Sheets(currentBook.Sheets.Count))
tsrSheet.name = "TSR"
Else
tsrSheet.Cells.Clear
End If
wb.Sheets(1).UsedRange.Copy tsrSheet.Range("A1")
wb.Close False
tsrSheet.Activate
With ActiveSheet.UsedRange
ActiveSheet.Rows(.Rows.Count).Delete
End With
Application.ScreenUpdating = True
End Sub