Documenten

AFAS Profit bijlagen exporteren (Powershell)

AFAS Profit bijlagen exporteren is in bulk helaas niet zo eenvoudig. Als je een keer een enkele bijlage uit een AFAS Profit dossier nodig hebt ga je eenvoudig in de applicatie naar het desbetreffende dossieritem en download je de bijlage. Maar wat als je nou van alle abonnementen uit één groep of administratie alle bijlages wil exporteren om deze in een andere applicatie in te lezen?

Dit leek me wel een mooie Powershell oefening en na enig uitstel ben ik er maar eens voor gaan zitten. Ik sla de voorbereidende stappen in AFAS Profit even over in deze post, maar ik zal verwijzen naar de bestaande instructies voor die stappen.

Wat gaan we doen?

Doel: Alle bijlages uit de abonnementsdossiers opslaan buiten AFAS Profit. Per abonnement maken we een map aan en daar worden alle bijlages die bij dat abonnement gevonden worden opgeslagen.

Stappenplan:

  1. Connectoren aanmaken in AFAS Profit
  2. Connectoren autoriseren in AFAS Profit
  3. Powershell script maken met een aantal functies:
  4. Draaien export

Stap 1 en 2 ga ik nu niet al te veel tijd aan besteden, als je de instructies volgt die hier staan moet je hier wel uit komen, als je geen idee hebt hoe dat werkt kan je het beste mij of een consultant even een berichtje sturen 🙂

Wel heb ik de twee getconnectoren die ik in dit voorbeeld gebruik hier staan zodat je deze kan gebruiken en/of aanpassen. (zip)

Powershell

Zoals aangegeven gaan we het exporteren van de files doen middels Powershell en de AFAS Profit getconnectoren. In dit geval heb ik Powershell 6.2 gebruikt in verband met een Invoke-RestMethod functionaliteit.

Het script is opgebouwd uit een aantal functies die ik vervolgens aanroep in een runner die de daadwerkelijke uitvoering doet. Onderaan staat een linkje naar de hele file, maar ik loop hier even door de scriptblokken heen, ik heb overal de url en autorisatie tokens aangepast:

Functie: ProfitAuthorisatie

function ProfitAuthorisatie {
    # Bouw de autorisatie header voor AFAS Profit
    $token = '<token><version>1</version><data>****</data></token>'
    $encodedToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($token))
    $authValue = "AfasToken $encodedToken"
    $Headers = @{
        Authorization = $authValue
    }
    $Headers
    return
}

Deze functie bouwt de autorisatie header op die we nodig hebben voor het aanroepen van de REST API van AFAS Profit. Deze code wordt een aantal keer aangeroepen in de komende functies. Vergeet niet je eigen Autorisatie token in te voeren.

Functie: GetAbo

function GetAbo {
    param (
        [int32]$administratie
    )
    # Definieer de URL voor de Profit omgeving
    $url = 'https://****/profitrestservices/connectors/DossierBijlagen?filterfieldids=AdministratieAbo%3BAdministratieProject&filtervalues=' + $administratie + '%3B' + $administratie + '&operatortypes=1%3B1&skip=-1&take=200'
    # Connect and retrieve the table
    $auth = ProfitAuthorisatie
    ((Invoke-WebRequest -Uri $url -UseBasicParsing -Headers $auth).content | ConvertFrom-Json).Rows
}

Deze functie haalt een lijst op van alle abonnementen die dossieritems hebben. Ik haal direct ook de verschillende dossieritem ID’s op die ik later nodig heb om de bijlagen op te sporen. De functie heeft een parameter nodig om te kunnen werken, dit is de administratiecode waarvan je de abonnementen op wil halen. Je geeft deze code als parameter mee wanneer je het uiteindelijke script aanroept.

Functie: GetBijlagen

function GetBijlagen {
    param (
        [int32]$DossieritemID
    )
    # Definieer de URL voor de Profit omgeving
    $url_dossier = 'https://****/profitrestservices/connectors/AbonnementenExport?filterfieldids=DossieritemID&filtervalues=' + $DossieritemID + '&operatortypes=1&skip=-1&take=-1'
    # Connect and retrieve the table
    $auth = ProfitAuthorisatie
    ((Invoke-WebRequest -Uri $url_dossier -UseBasicParsing -Headers $auth).content | ConvertFrom-Json).Rows
}

Deze functie heeft het ID van het dossieritem als input parameter nodig. Dit is een van de velden die als resultaat uit de GetAbo functie is gekomen. De reden dat we los de bijlagen op moeten halen is dat de GUID en de filename niet direct in het dossieritem beschikbaar zijn. Daar komt bij dat een enkel dossieritem weer meerdere bijlagen kan hebben. De output hier is een object/array met alle bijlages die beschikbaar zijn bij dit dossieritem.

Functie: DownloadBijlagen

function DownloadBijlagen {
    param (
        [string]$filename,
        [string]$guid,
        [string]$map,
        [string]$abo
    )

    # Definieer de URL voor de Profit omgeving
    $url_download = 'https://****/profitrestservices/fileconnector/' + $guid + '/' + $filename 
    # Connect and retrieve the table
    $auth = ProfitAuthorisatie
    $fileout = $map + '\' + $abo + '-' + $filename 
    $download_error = 0

    # Voorkomen dat we lege files wegschrijven omdat de download niet uitgevoerd kan worden.
    try {
        $tempfile = Invoke-RestMethod -Uri $url_download -Method Get -Headers $auth 
    }
    catch {
        Write-Host $_ -fore Red
        $download_error = 1
    }
    
    if ($download_error -eq 0) {
        $bytes = [System.Convert]::FromBase64String($tempfile.filedata)
        [IO.File]::WriteAllBytes($fileout, $bytes)
        Write-Host $filename "- Succesvol weggeschreven in"  $fileout -ForegroundColor green
    } 
}

Op basis van de items in de lijst die uit GetBijlagen gekomen is kunnen we de files gaan downloaden. Je hebt sowieso de filename en de guid nodig om de fileconnector (subjectconnector) aan te kunnen roepen. Daarnaast geef ik de map mee waar we de file op gaan slaan en het abonnementsnummer (deze neem ik op in de filename, dit is wel een punt, het is niet uitgesloten dat dit dubbele bestanden op kan leveren, in ons geval komt dat niet voor, maar technisch zou je hier bestanden kunnen overschrijven).

In dit stukje code zit ook een error check, heel af en toe kan een file niet goed gedownload worden, dit leverde lege bestanden op. Om dat te voorkomen vang ik die error af (en meld dat in de output) en doe dan dus geen download.

Op dit moment levert dit wel nog lege mappen op als de enkele bijlage bij een abonnement niet goed gedownload kan worden, maar dat zou je simpel op kunnen lossen als dat een probleem is.

Functie: ScriptUitvoeren

function ScriptUitvoeren {
    param (
        [int32]$administratie
    )
    
    # Eerst Getabo
    $records = GetAbo $administratie

    # Per Abo dossieritems ophalen
    foreach ($record in $records) {
        
        # Map bepalen voor het eventueel opslaan van bijlagen
        $map = "C:\Exports\" + $record.Abonnement  

        # Bijlagenlijst per dossieritem maken
        $bijlagenlijst = GetBijlagen $record.DossieritemID

        # Als de map voor het abonnement nog niet bestaat deze aanmaken
        If (!(test-path $map) -And $bijlagenlijst.count -gt 0) {
            New-Item -ItemType Directory -Force -Path $map
        }

        # Per bijlage file downloaden
        foreach ($bijlage in $bijlagenlijst) {
            DownloadBijlagen $bijlage.Naam $bijlage.Bijlage $map $record.Abonnement
        }
    }
}

Dit is de functie die we aanroepen als we het script gaan draaien, je zou deze functie ook direct in de code aan kunnen roepen. Gezien ik het script per administratie wil kunnen draaien heb ik er voor gekozen om hem los aan te roepen. De functie heeft het administratienummer als parameter nodig.

In dit geval is de map waar we de bijlagen opslaan c:\exports\ maar daar kan je van maken wat je wil.

Je ziet in deze funtie dat alle eerdere functies stap voor stap opgeroepen worden en de output daarvan weer als input in een andere functie gestopt wordt. Er worden twee nested foreach loops gebruikt om door alle abonnementen en dossieritems heen te lopen.

Tot slot

Het script is zeker niet perfect, ik zou de lege mappen nog op kunnen ruimen en wat betere logging toe kunnen passen, maar voor ons doel was dit voldoende. Als je eventueel vragen hebt over het script kan je die in de comments stellen.

Het script is hier te downloaden en in te zien. Nadat je de ps1 file gedraaid hebt kan je met “ScriptUitvoeren #” het script starten (vervang # door het administratienummer).

Documenten

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Deze website gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie-gegevens worden verwerkt.