<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Xavier Garonnat</title>
    <description>The latest articles on DEV Community by Xavier Garonnat (@xgaronnat).</description>
    <link>https://dev.to/xgaronnat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F827411%2Fe802e82f-9c88-4a36-9526-7fb377b6276c.jpeg</url>
      <title>DEV Community: Xavier Garonnat</title>
      <link>https://dev.to/xgaronnat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xgaronnat"/>
    <language>en</language>
    <item>
      <title>What is the weight of my custom apps...</title>
      <dc:creator>Xavier Garonnat</dc:creator>
      <pubDate>Wed, 12 Oct 2022 14:16:27 +0000</pubDate>
      <link>https://dev.to/xgaronnat/what-is-the-weight-of-my-custom-apps-4h7m</link>
      <guid>https://dev.to/xgaronnat/what-is-the-weight-of-my-custom-apps-4h7m</guid>
      <description>&lt;p&gt;Question (from one of our customer): what is the weight of our custom/PTE apps compared to the standard/base app.&lt;/p&gt;

&lt;p&gt;Let's &lt;a href="https://github.com/microsoft/BusinessCentralApps/tree/main/Layers/W1/BaseApp"&gt;download&lt;/a&gt; the base app objects and script some powershell to get some quick insight :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cMYaEi2z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94u81zudcmnw4wdvsqe4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cMYaEi2z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94u81zudcmnw4wdvsqe4.png" alt="Image description" width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download script &lt;a href="https://drive.google.com/file/d/172iysQ1a5MfVFQ99P7EWgcIcSTJNMoRt/view?usp=sharing"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>businesscentral</category>
      <category>powershell</category>
    </item>
    <item>
      <title>Splitting Warehouse Shipment lines in multiple headers in Business Central</title>
      <dc:creator>Xavier Garonnat</dc:creator>
      <pubDate>Wed, 15 Jun 2022 15:27:43 +0000</pubDate>
      <link>https://dev.to/xgaronnat/splitting-warehouse-shipment-lines-in-multiple-headers-in-business-central-19a1</link>
      <guid>https://dev.to/xgaronnat/splitting-warehouse-shipment-lines-in-multiple-headers-in-business-central-19a1</guid>
      <description>&lt;p&gt;AL extensibility challenge : how to spread automatically Warehouse Shipment Lines on multiple Warehouse Shipment Header without being too much intrusive ? &lt;em&gt;(with the constraint that the count of lines per document should now exceed a fixed value)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Just find the right event in the "Get Source Document" report and force the creation of a new header by setting WhseHeaderCreated to false when the condition is met :-)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    [EventSubscriber(ObjectType::Report, Report::"Get Source Documents", 'OnSalesLineOnAfterGetRecordOnBeforeCreateShptHeader', '', false, false)]
    local procedure OnSalesLineOnAfterGetRecordOnBeforeCreateShptHeader(SalesLine: Record "Sales Line"; var WarehouseRequest: Record "Warehouse Request"; var WarehouseShipmentHeader: Record "Warehouse Shipment Header"; var WhseHeaderCreated: Boolean; var OneHeaderCreated: Boolean; var IsHandled: Boolean);
    var
        WhseShipmentLine: Record "Warehouse Shipment Line";
    begin

        IF WarehouseShipmentHeader."No." = '' then
            exit;

        WhseShipmentLine.Reset();
        WhseShipmentLine.SetRange("No.", WarehouseShipmentHeader."No.");
        if WhseShipmentLine.Count = &amp;lt;MaxLinePerDocument&amp;gt; then
            WhseHeaderCreated := false; //create new Whse Shipment Header

    end;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I like simplicity :-)&lt;/p&gt;

&lt;p&gt;Edit : the event is located here &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqhxt7n1az8q1ota63kp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqhxt7n1az8q1ota63kp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Monitoring Business Central performance with Azure Troubleshootings Guide (preview)</title>
      <dc:creator>Xavier Garonnat</dc:creator>
      <pubDate>Fri, 08 Apr 2022 10:13:02 +0000</pubDate>
      <link>https://dev.to/xgaronnat/monitoring-business-central-performance-with-azure-troubleshootings-guide-preview-1ae</link>
      <guid>https://dev.to/xgaronnat/monitoring-business-central-performance-with-azure-troubleshootings-guide-preview-1ae</guid>
      <description>&lt;p&gt;To analyze performances issues in Business Central, top entry points are for sure &lt;a href="https://aka.ms/BCtelemetry"&gt;Telemetry&lt;/a&gt; and Troubleshooting Guides delivered as &lt;a href="https://github.com/microsoft/BCTech/tree/master/samples/AppInsights/TroubleShootingGuides"&gt;Jupyter Notebooks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Jupyter Notebooks are provided as .ipynb files (Performance-overview-TSG.ipynb for example) : these files requires Azure Data Studio, kqlmagic library, etc. (with state of the art .ini configuration files :-)&lt;/p&gt;

&lt;p&gt;I'm not a big fan of using desktop resources to analyze performance of SaaS environments... so I jumped into &lt;strong&gt;online Troubleshooting Guides&lt;/strong&gt;. This feature is still in &lt;strong&gt;preview&lt;/strong&gt; but quite stable honestly.&lt;/p&gt;

&lt;p&gt;The feature is available in the Azure Application Insight resource and fully replace Jupyter Notebooks as you can aggregate KQL queries in a very similar way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ThiRRh6W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7uqekv1kevkfsvs5b99.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ThiRRh6W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7uqekv1kevkfsvs5b99.png" alt="Jupyter Notebook" width="880" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we went to "copy/paste" existing KQL queries from Jupyter notebooks/samples into a single online Troubleshooting Guide, most of them regarding performance like Long Running queries (RT0005), Database locks (RT0012), AL Performance (RT0018)...&lt;/p&gt;

&lt;p&gt;Apart that it's an online feature (with by-design benefits), we liked the ability to consolidate Tenant ID/environments and the usage of Parameters block to filter events on Tenant ID, environment, company, client type, object type/ID, ... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XUUWLJqq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3krmkfaspsg2ymicepg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XUUWLJqq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3krmkfaspsg2ymicepg.png" alt="Jupyter Notebook" width="880" height="57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can obviously mix graphics and data parts, and all data can be downloaded in raw files in case of.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QLcyZDlt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y54ty3yvbk6wgyoqdda4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QLcyZDlt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y54ty3yvbk6wgyoqdda4.png" alt="Troubleshooting Guide Performance" width="880" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FRrzrb62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3tnqk1w97e5fpuzpfg0y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FRrzrb62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3tnqk1w97e5fpuzpfg0y.png" alt="Download Data" width="880" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On top of this, it's very easy to deploy as the Troubleshooting guide is a single JSON file that you import into any Azure Tenant/Application Insight resource...&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using PowerShell Class to generate JSON for Batch Call API with Business Central</title>
      <dc:creator>Xavier Garonnat</dc:creator>
      <pubDate>Tue, 08 Mar 2022 16:16:11 +0000</pubDate>
      <link>https://dev.to/xgaronnat/using-powershell-class-to-generate-json-for-batch-call-api-with-business-central-3oji</link>
      <guid>https://dev.to/xgaronnat/using-powershell-class-to-generate-json-for-batch-call-api-with-business-central-3oji</guid>
      <description>&lt;p&gt;In this first article, I will showcase how to use PowerShell Class to easily create JSON document for Business Central API.&lt;/p&gt;

&lt;p&gt;This sample was designed to do massive insert of Sales Invoice by lot of 100 using Batch Call : see this excellent &lt;a href="https://www.kauffmann.nl/2020/12/18/batch-calls-with-business-central-apis-1-basic-operation/"&gt;article&lt;/a&gt; for more details about API Batch Call.&lt;/p&gt;

&lt;p&gt;The "trick" is to use &lt;strong&gt;PowerShell Class&lt;/strong&gt; and (nested) Arrays to generate the right JSON document.&lt;/p&gt;

&lt;p&gt;We will start by designing Sales Invoice and Sales Invoice Line in a very simple way (using [] for Array definition to store multiple lines).&lt;/p&gt;

&lt;p&gt;Theses classes are intended to be used with &lt;a href="https://docs.microsoft.com/es-es/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesinvoice"&gt;Sales Invoice API&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/es-es/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesinvoiceline"&gt;Sales Invoice Line API&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SalesInvoiceClasss
{
    [string] $customerId 
    [SalesInvoiceLineClass[]] $salesInvoiceLines

    [void]addLine([SalesInvoiceLineClass]$SalesInvoiceLine) 
    {
        $this.salesInvoiceLines += $SalesInvoiceLine
    }
}

class SalesInvoiceLineClass
{
    [string] $accountId 
    [decimal] $quantity  
    [decimal] $unitPrice     
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use &lt;a href="https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/webservices/use-odata-batch#request-body"&gt;Batch Call&lt;/a&gt; we need to POST requests. We will define classes to manage the list of request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ListOfRequestClass
{
    [RequestClass[]] $requests

    [void]addRequest([RequestClass]$request) 
    {
        $this.requests += $request
    }
}

class RequestClass
{
    [string] $method = "POST"
    [string] $id  = ""
    [string] $url = ""
    [ContentTypeClass] $headers     
    [SalesInvoiceClass] $body    
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note the AddLine()/AddRequest() method to manage the corresponding collections inside each class and the default "POST" value.&lt;/p&gt;

&lt;p&gt;We need one last (utility) class to have a default value in the header :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ContentTypeClass {
    [string] ${Content-Type} = "application/json"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can instantiate objects to create an invoice with two lines :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Init a new Sales Invoice line
$salesInvoiceLine1 = New-Object SalesInvoiceLineClass
$salesInvoiceLine1.accountid = "$accountid"
$salesInvoiceLine1.quantity = 1
$salesInvoiceLine1.unitPrice = 10

# Init a new Sales Invoice line
$salesInvoiceLine2 = New-Object SalesInvoiceLineClass
$salesInvoiceLine2.accountid = "$accountid"
$salesInvoiceLine2.quantity = 2
$salesInvoiceLine2.unitPrice = 15

# Init a new Sales Invoice 
$salesInvoice = New-Object SalesInvoiceClass
$salesInvoice.customerId = "$customerid"
$salesInvoice.addLine($salesInvoiceLine1)
$salesInvoice.addLine($salesInvoiceLine2)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The corresponding JSON using command $salesInvoice | ConvertTo-Json is :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "customerId":  "4636f8d6-c141-ec11-bb7b-000d3a256200",
    "salesInvoiceLines":  [
                              {
                                  "accountId":  "2236f8d6-c141-ec11-bb7b-000d3a256200",
                                  "quantity":  1,
                                  "unitPrice":  10
                              },
                              {
                                  "accountId":  "2236f8d6-c141-ec11-bb7b-000d3a256200",
                                  "quantity":  2,
                                  "unitPrice":  15
                              }
                          ]
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now build a list of request containing 100 invoices (using the Invoice in the body request):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$listofrequest = New-Object ListOfRequestClass

$numberOfInvoices = 100
for($i = 0; $i -lt $numberOfInvoices ; $i++) 
{
    # Init a new request
    $request = New-Object RequestClass
    $request.id = $i
    $request.url = "companies($companyid)/salesInvoices" 
    $request.headers = $ContentType
    $request.body = $salesInvoice

    $listofrequest.addRequest($request)
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please find the result &lt;a href="https://drive.google.com/file/d/1ZyKgLaWknzm7J6CmfFs7-cmg2KdHjWns/view?usp=sharing"&gt;here&lt;/a&gt; : a full JSON document that can be used with your batch API &lt;a href="https://api.businesscentral.dynamics.com/v2.0/Production/api/v2.0/%24batch"&gt;URL&lt;/a&gt; to create 100 invoices in one call.&lt;/p&gt;

&lt;p&gt;Enjoy !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GcvwKMWO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l83q0zvabxswcnsrvx5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcvwKMWO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l83q0zvabxswcnsrvx5h.png" alt="Using Powershell Class to generate JSON for Batch Call API with Business Central" width="668" height="1159"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>rest</category>
      <category>businesscentral</category>
      <category>powershell</category>
    </item>
  </channel>
</rss>
