Rechtstreeks connectoren aanroepen/bij de AFAS API via de analysetool in Profit

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

  1. 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.
  2. voeg een eigen App connector toe met de relevante updateconnector en connector voor het XSD schema: Eigen app connector toevoegen - AFAS Help Center
  3. 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.
  4. 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
  5. 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.
  6. 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.
  7. 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

2 likes

Beste Robert,

Geweldig artikel!
Nu ben ik best wel technisch onderlegd, dus dit gaat mij wel lukken, maar betwijfel of iedereen dit zonder kennis van scripting dit zomaar kan..
Misschien handig om een Excel voorbeeld toe te voegen waar alles al in staat (ex apitoken en omgeving uiteraard)?

Met vriendelijke groet,
Peter

Hoi Peter,

Goed idee. Ik heb er eentje opgeschoond van alle vrije velden en data maar kan hem hier niet uploaden; waarschijnlijk een bewuste beperking in het forum.
Op afroep beschikbaar :slight_smile: mag via een mailtje naar robert@rocrad.com

Super artikel! Zou dat voorbeeld ook graag ontvangen.

Stuur me een mailtje dan krijg je hem!