D365 Business Central

Business Central Attachments with standard API – Part 1 Basic Explanation

A nice feature which is explained fairly well in the Microsoft docs site but it is especially nice to have a working example. (https://docs.microsoft.com/en-us/dynamics-nav/api-reference/v1.0/api/dynamics_attachment_patch). The attachments API itself actually points to the “Incoming Documents” feature of BC, so terminology might catch you out. The scope of the API therefore covers whatever you can use “Incoming Document” for: Purchase Invoice/Credit, Sales Invoice/Credit and Journal lines.

You need to use to HTTP calls to make this one work and this is the pattern:

Firstly you POST a simple line to say what you are attaching to i.e. our Invoice/Credit record or our journal line. This must be the ID or SystemID value of that record. How this plays out in a practical sense will depend on how you implement the API with your solution. In the scenario where you create a purchase invoice and then have an attachment of that latched against it you will need to perform the creation of the purchase invoice record first – a follow up post on this. Here is how the first action looks:

https://api.businesscentral.dynamics.com/v2.0/<tenantID>/uat/api/v1.0/companies(companyID)/attachments

Body:

{    “parentId”: “5a086bc7-195f-eb11-89f9-0022481ab2d5”,    “fileName”: “Example.pdf”}

How it looks in a HTTP client like Postman. Note that the “filename” property is just a value you choose. So if this was part of a solution you might do it as the invoice number or document no. of the journal line you created before this step

Now the PATCH part is where the order of this becomes very important. You need a value from the POST to do the PATCH…..😮

This is the response I get from doing the POST command. It is the ID value which is new to the story and is how I perform the actual attachment process. POST is just to create the Incoming Document record….penny drops 🙈

Once the above is known then the PATCH command shown in Microsoft Docs becomes very easy to follow. Here is the command: PATCH businesscentralPrefix/companies({companyId})/attachments(parentId={parentId},id={attachmentId})/content . Simply add the information we now know. So in my case, with the above screenshot, my “parentID” is 5a086bc7-195f-eb11-89f9-0022481ab2d5 and my “id” is 7a1f7c6c-1e5f-eb11-89f9-0022481ab2d5. Notice that the odata.etag has been provided from the previous POST step so you can add that in as well for the “Headers” of the PATCH command. Here is what I mean:

etag is there to track the changes – make sure someone else hasn’t modified the record since you last got it. It is possible to use a wildcard here if needs must

In postman at least the body of the PATCH command is something like below but in a real solution you just need to make sure you pass a binary file:

In postman if you are testing this you can select a file to work with and it will pop open your file explorer.

Once each of the mentioned are in place you can go ahead with the PATCH. You should get a 204 status response but there will be no body type output.

When you head over to BC though you will see your record, which started life as our ID no has an “Incoming Document” record against it.
Here is the record in the Incoming Documents table. Once posted a user will be able to view document as well.
D365 Business Central, PowerApps

Business Central Images to a Canvas Power App Gallery

For those who missed it I did a session for BC Tech Talk last year:

During that session I showed how to get a single image for an item record with an API call (35mins and beyond). The method was very simple to create a custom connector for the standard Picture API and just add a extra bit of text. Similar to this: https://api.businesscentral.dynamics.com/v1.0/8d0632b1-47bf-41fe-ba13-a838adf98c48/sandbox/api/v1.0/companies({companyID})/items({itemID})/picture({pictureID})/content

The green text pulls the image directly into an image control in the canvas app 👍. I mention in the video that you could have the picture images in the main gallery view – it will be slower this way but I was asked to at least explain how. The standard API isn’t that helpful here – VERY HAPPY TO BE TOLD HOW TO USE IT CORRECTLY – the endpoint doesn’t interact in the same was as a HTTP request would and it wants to produce a table of data and no matter how I work with the connector with the available formulas I just get errors. Can see from the Power Users forum this is a similar theme with others:

So to get around this a new page is needed with some extra capability. The end goal here is to create a custom connector for use in powerapps that gives the base64 image value for BC item records. I took inspiration for the solution from this blog which I’ve adapted slightly for latest version (at the time of writing being 17.2 – may have changed since): How to get picture from MediaSet through standard APIs. – Dynamics 365 Business Central Community

Final code is on github – Code: https://github.com/JAng13sea/Blogs/tree/master/ItemImages – but in essence you need a new API page for the item table. A field on the API page which is populated by a codeunit return value of text which has been converted into base64:

    procedure "Pic as JSON"(ItemNo: Code[20]) : Text;
    var
        Item: Record Item;
        TenantMedia: Record "Tenant Media";
        PicText: Text;
        PicInstr: InStream;
        JObject: JsonObject;
        JToken: JsonToken;
        TempBlob: Codeunit "Temp Blob";
        PicOStr: OutStream;
        Base64: Codeunit "Base64 Convert";
    begin
        Item.Get(ItemNo);
        If Item.Picture.Count = 0 then
            exit('');
        TenantMedia.Get(Item.Picture.Item(1));
        TenantMedia.CalcFields(Content);
        if TenantMedia.Content.HasValue then begin
            Clear(PicText);
            Clear(PicInstr);
            TenantMedia.Content.CreateInStream(PicInstr);
            PicText := Base64.ToBase64(PicInstr);
            JObject.Add('picture',PicText);
            JObject.SelectToken('picture',JToken);
        end;
        exit(JToken.AsValue().AsText());
    end;

Note that it has been added into a JSON structure to make it easy for other solutions to read it. From here you will need to create a custom connector for Power Platform. I did another video on this so check it out if you need guidance on that part:

Once the connector is in place and you have pulled the data from BC into a collection in PowerApps you can address the image value in the gallery. When using a gallery in PowerApps a predefined method exists for stating each row of the gallery – ThisItem – the value passed from BC is in Base64 but it needs decoding in PowerApps for an image control to display it. In the image control add the text “data:image; application/octet-stream; base64,” & ThisItem.picture

Depending on the volume of items with images this type of call could be very long so tread with caution. If you happen to be using images with other data or storing other blobs this pattern is a way to get the data into PowerApps.