Als AFAS-beheerder wil je vaak data uit AFAS halen, combineren en vervolgens terugstoppen. (ik gebruik dit bijvoorbeeld om op basis van een aantal criteria extra verlofdagen toe te kennen.) Hiervoor is vaak een omslachtig importproces, of dure of complexe middleware nodig. Je kunt dit ook relatief eenvoudig met slim gebruik van Excel en VBA.
Hieronder een uitwerking hoe je met een VBA-script de API’s van AFAS aanroept via een analyse. De structuur is zo opgezet dat ChatGPT zonder brondata toch goed kan ondersteunen bij het maken van de scripts. De insteek is dat dit ook voor een “niet programmeur” die AI-assisted werkt toch goed uit te voeren is.
Waarom Excel VBA + ChatGPT?
- Excel VBA is beschikbaar voor vrijwel iedereen en vereist geen extra licenties of software. Het is krachtig genoeg om API-aanroepen te doen en gegevens te verwerken.
- ChatGPT helpt je om complexe API-aanroepen, XML-structuren en foutafhandeling snel begrijpelijk te maken en voorbeeldcode te genereren op maat van jouw situatie.
- De combinatie maakt het voor een beheerder toegankelijk om analyses te maken en connectoren aan te roepen zonder zware programmeerkennis.
Voordelen
- AFAS biedt uitgebreide documentatie, waaronder XSD-schema’s en cURL-examples, via connect.afas.nl
- Volledig geïntegreerd in AFAS, geen externe tools nodig.
- Data blijft binnen de analysetool, geen handmatige exports meer. Geen data naar derde partijen
- VBA automatisering zorgt voor snelle en betrouwbare updates.
- Makkelijk aanpasbaar door beheerders met basis VBA kennis. Programmatuur is makkelijk leesbaar voor AI en mens
- Transparantie: je ziet en beheert zelf wat er naar AFAS gaat.
- Snel testen, aanpassen en uitbreiden.
Praktisch: zo werkt het
- Gebruik de analysetool in AFAS om verschillende datasets te combineren tot één overzichtelijk geheel. Dit geeft je de mogelijkheid om datasets te koppelen en te filteren, zodat je precies de benodigde data voor je connector samenstelt.
- voeg een eigen App connector toe met de relevante updateconnector en connector voor het XSD schema: Eigen app connector toevoegen - AFAS Help Center
- Sla in de analysetool een VBA-script op dat automatisch de juiste connectoren aanroept. Zo kun je vanuit dezelfde analyse, zonder export/import, direct via de API updates doorvoeren.
- Bekijk het XSD-schema op connect.afas.nl om te begrijpen welke velden en attributen de connector vereist. > XSD-schema ophalen met DataConnector (AppConnectorData) - AFAS Help Center
- Gebruik de curl-voorbeeldaanroepen om de technische details van de API aanroepen te leren kennen. Connect.afas.nl genereert automatisch voorbeelden van de cURL voor je.
- Maak een VBA-script dat de SOAP-requests bouwt op basis van jouw dataset en de API-specificaties. ChatGPT kan hiermee uitstekend uit de voeten als je deze het XSD schema en de voorbeeld cURL voert.
- Run het VBA-script direct vanuit de analysetool om de connectoren aan te roepen en data bij te werken in AFAS.
Hieronder een uitwerking in detail met een voorbeeld:
Ik bouw hier stap voor stap een macro op met placeholders; daarna een volledig script dat bovenstaande toepast. Een paar kanttekeningen vooraf:
Het lukt me niet om de natuurlijke marking van het forum te omzeilen waardoor er een aantal blokken script niet grijs en dan weer wel grijs zijn.
Een script kan altijd netter/mooier. Bijvoorbeeld door het script modulair te maken kun je blokken makkelijker hergebruiken.
Er zijn opties die ik niet toepas die makkelijk toe te voegen zijn in het vba script die moeilijker zijn in excel. Denk aan:
- Logica op ontbrekende waarden
- formats van waarden
- filters op waarden
etc. Als het in een veld in de excel staat mag je je eigen logica daarop bouwen.
Stap 1: Voorbereiding van het Excel-werkblad
• Zorg dat de velden voor de connector op één werkblad staan met een duidelijke naam: [Vul hier je tabbladnaam in]
• Zorg dat hierin de kolommen met de gegevens staan, bijvoorbeeld:
- Kolom A = veld 1
- Kolom B = veld 2
- Kolom C = veld 3
• Maak een tweede tabblad aan voor fouten
Hiermee krijg je de tabel die de connector moet gaan inlezen.
Stap 2: VBA module opbouwen
Via alt + F11 benader je de VBA modules, voeg een nieuwe module in
Definieer vaste waarden en API-details als constante strings bovenaan de Macro, dynamische waardes uit velden doe je later:
Const [attribuut X] As String = "[Vul hier vaste warden van attributen in, deze zijn gedefinieerd in het XSD schema]
Const Action As String = "[Vul hier Insert/Update/Delete in]
Const ConnectorType As String = “[Vul hier connectornaam in]” ’ Bijvoorbeeld “FbItemCodeSupplier”
Const ConnectorVersion As String = “[Vul hier connectorversie in]” ’ Bijvoorbeeld “1”
Const ApiUrl As String = “[Vul hier je SOAP endpoint URL in]”
Const ApiToken As String = “[Vul hier je Base64 API-token in]”
Stap 3: Initialisatie van werkbladen en HTTP-object
In VBA definiëren we nu een aantal zaken die zorgen dat:
- Het data-werkblad bekend is,
- Bepaald wordt tot welke rij de macro moet lezen
- Er een schoon foutentabblad beschikbaar is om fouten te loggen,
- Alles klaar staat om HTTP-requests te maken.
Dim ws As Worksheet, wsErrors As Worksheet
Dim lastRow As Long, errorRow As Long
Dim http As Object
Set ws = ThisWorkbook.Worksheets(“[Vul hier je tabbladnaam in]”)
lastRow = ws.Cells(ws.Rows.Count, “[Vul hier een kolomletter van een verplicht veld in]”).End(xlUp).Row
On Error Resume Next
Set wsErrors = ThisWorkbook.Worksheets(“[Vul hier naam foutentabblad in]”)
On Error GoTo 0
If wsErrors Is Nothing Then
Set wsErrors = ThisWorkbook.Worksheets.Add
wsErrors.Name = “[Vul hier naam foutentabblad in]”
wsErrors.Range(“[Vul hier in welke cellen gevuld moeten worden in de errorlog, bijv A1:D1]”).Value = Array(“Rij”, “[veld 1]”, “[veld 2]”, “Foutmelding”)
Else
wsErrors.Cells.ClearContents
wsErrors.Range(“[Vul hier in welke cellen gevuld moeten worden in de errorlog, bijv A1:D1]”).Value = Array(“Rij”, “[veld 1]”, “[veld 2]”, “Foutmelding”)
End If
errorRow = 2
Set http = CreateObject(“MSXML2.XMLHTTP”)
Stap 4: Loop door de rijen en bouw de SOAP-request
In VBA definiëren we nu een aantal zaken die zorgen dat:
- per regel belangrijke velden uit excel gezocht worden
- Een stuk xml volgens het schema wordt opgebouwd, met vaste en dynamische waarden.
- Dit XML-bericht in een SOAP-bericht wordt gezet.
- Vaste waardes meegenomen worden.
Dim row As Long
Dim crId As String, itCd As String, itSp As String
Dim dataXml As String, soapEnvelope As String
For row = [Vul hier start rij in (in analyses vaak 5)] To lastRow
Application.StatusBar = "Verwerken regel " & row & " van " & lastRow
[veld1] = Trim(ws.Cells(row, "[Vul hier kolomletter veld1 in]").Value)
[veld2] = Trim(ws.Cells(row, "[Vul hier kolomletter veld2 in]").Value)
[veld3] = Trim(ws.Cells(row, "[Vul hier kolomletter veld3 in]").Value)
dataXml = "<[Vul hier root element naam in (connectornaam)] xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">" & _
"<Element " & _
"[Vul hier attribuutnaam 1 in]=""[Vul hier attribuutwaarde 1 in]"" " & _
"[Vul hier attribuutnaam 2 in]=""[Vul hier attribuutwaarde 2 in]"">" & _
"<Fields Action=""[Vul hier Action attribuut in]"">" & _
"<veld1>[Vul hier veld1 in]</veld1>" & _
"<veld2>[Vul hier veld2 in]</veld2>" & _
"<veld3>[Vul hier veld3 in]</veld3>" & _
"<veld4>[Vul hier veld4 in]</veld4>" & _
"<veld5>[Vul hier veld5 in]</veld5>" & _
"<veld6>[Vul hier veld6 in]</veld6>" & _
"<veld7>[Vul hier veld7 in]</veld7>" & _
"<veld8>[Vul hier veld8 in]</veld8>" & _
"<veld9>[Vul hier veld9 in]</veld9>" & _
"<veld10>[Vul hier veld10 in]</veld10>" & _
"<veld11>[Vul hier veld11 in]</veld11>" & _
"<veld12>[Vul hier veld12 in]</veld12>" & _
"<veld13>[Vul hier veld13 in]</veld13>" & _
"<veld14>[Vul hier veld14 in]</veld14>" & _
"<veld15>[Vul hier veld15 in]</veld15>" & _
"<veld16>[Vul hier veld16 in]</veld16>" & _
"<veld17>[Vul hier veld17 in]</veld17>" & _
"<veld18>[Vul hier veld18 in]</veld18>" & _
"<veld19>[Vul hier veld19 in]</veld19>" & _
"<veld20>[Vul hier veld20 in]</veld20>" & _
"</Fields>" & _
"</Element>" & _
"</[Vul hier root element naam in]>"
soapEnvelope = _
"<?xml version=""1.0"" encoding=""utf-8""?>" & _
"<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" " & _
"xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" " & _
"xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
"<soap:Body>" & _
"<Execute xmlns=""urn:Afas.Profit.Services"">" & _
"<connectorType>" & ConnectorType & "</connectorType>" & _
"<connectorVersion>" & ConnectorVersion & "</connectorVersion>" & _
"<dataXml><![CDATA[" & dataXml & "]]></dataXml>" & _
"</Execute>" & _
"</soap:Body>" & _
"</soap:Envelope>"
Stap 5: Versturen van de request en foutafhandeling
http.Open "POST", ApiUrl, False
http.setRequestHeader "Content-Type", "text/xml"
http.setRequestHeader "Authorization", "AfasToken " & ApiToken
http.send soapEnvelope
If http.Status <> 200 Then
wsErrors.Cells(errorRow, "A").Value = row
wsErrors.Cells(errorRow, "B").Value = [veld 1]
wsErrors.Cells(errorRow, "C").Value = [veld 2]
wsErrors.Cells(errorRow, "D").Value = http.Status & " - " & http.responseText
errorRow = errorRow + 1
End If
DoEvents
Next row
Stap 6: Afronden
Application.StatusBar = False
MsgBox “Updates voltooid! Fouten staan op het tabblad '” & “[Vul hier naam foutentabblad in]” & “'.”
End Sub
En hier een ingevuld voorbeeld zodat je een beeld hebt van hoe de data eruit moet zien
Voor de connector “FbItemCodeSupplier”:(omgeving en token anoniem)
Sub UpdateAlleRegelsInExcel()
Const vaIt As String = “2”
Const Action As String = “update”
Const ConnectorType As String = “FbItemCodeSupplier”
Const ConnectorVersion As String = “1”
Const ApiUrl As String = “https://12345.soap.afas.online/ProfitServices/AppConnectorUpdate.asmx”
Const ApiToken As String = “mijnapitoken”
Dim ws As Worksheet
Dim lastRow As Long
Dim row As Long
Dim http As Object
Dim soapEnvelope As String
Dim dataXml As String
Dim crId As String, itCd As String, itSp As String, deCr As String
Dim wsErrors As Worksheet
Dim errorRow As Long
Set ws = ThisWorkbook.Worksheets("laagste prijs")
lastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).row
' Maak of haal het error-tabblad op
On Error Resume Next
Set wsErrors = ThisWorkbook.Worksheets("AFAS Fouten")
On Error GoTo 0
If wsErrors Is Nothing Then
Set wsErrors = ThisWorkbook.Worksheets.Add
wsErrors.Name = "AFAS Fouten"
wsErrors.Range("A1").Value = "Rij"
wsErrors.Range("B1").Value = "CrId"
wsErrors.Range("C1").Value = "ItCd"
wsErrors.Range("D1").Value = "Foutmelding"
Else
wsErrors.Cells.ClearContents
wsErrors.Range("A1").Value = "Rij"
wsErrors.Range("B1").Value = "CrId"
wsErrors.Range("C1").Value = "ItCd"
wsErrors.Range("D1").Value = "Foutmelding"
End If
errorRow = 2
url = ApiUrl
token = ApiToken
Set http = CreateObject("MSXML2.XMLHTTP")
For row = 5 To lastRow
Application.StatusBar = "AFAS updates verwerken... Regel " & row & " van " & lastRow
crId = Trim(ws.Cells(row, "H").Value)
itCd = Trim(ws.Cells(row, "B").Value)
itSp = Trim(ws.Cells(row, "F").Value)
deCr = "true"
dataXml = "<FbItemCodeSupplier xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">" & _
"<Element VaIt=""" & vaIt & """ CrId=""" & crId & """>" & _
"<Fields Action=""" & Action & """>" & _
"<VaIc>1</VaIc>" & _
"<ItCd>" & itCd & "</ItCd>" & _
"<ItSp>" & itSp & "</ItSp>" & _
"<DeCr>" & deCr & "</DeCr>" & _
"</Fields>" & _
"</Element>" & _
"</FbItemCodeSupplier>"
soapEnvelope = _
"<?xml version=""1.0"" encoding=""utf-8""?>" & _
"<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" " & _
"xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" " & _
"xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
"<soap:Body>" & _
"<Execute xmlns=""urn:Afas.Profit.Services"">" & _
"<connectorType>" & ConnectorType & "</connectorType>" & _
"<connectorVersion>" & ConnectorVersion & "</connectorVersion>" & _
"<dataXml><![CDATA[" & dataXml & "]]></dataXml>" & _
"</Execute>" & _
"</soap:Body>" & _
"</soap:Envelope>"
http.Open "POST", url, False
http.setRequestHeader "Content-Type", "text/xml"
http.setRequestHeader "Authorization", "AfasToken " & token
http.send soapEnvelope
If http.Status <> 200 Then
wsErrors.Cells(errorRow, "A").Value = row
wsErrors.Cells(errorRow, "B").Value = crId
wsErrors.Cells(errorRow, "C").Value = itCd
wsErrors.Cells(errorRow, "D").Value = http.Status & " - " & http.responseText
errorRow = errorRow + 1
End If
DoEvents
Next row
Application.StatusBar = False
MsgBox "AFAS updates voltooid! Fouten (indien aanwezig) zijn gelogd op het tabblad 'AFAS Fouten'."
End Sub