279 lines
No EOL
49 KiB
XML
279 lines
No EOL
49 KiB
XML
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>alguidelines.dev - Business Central Design Patterns – Notifications</title><link>https://alguidelines.dev/docs/navpatterns/patterns/notifications/</link><description>Recent content in Notifications on alguidelines.dev - Business Central Design Patterns</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><atom:link href="https://alguidelines.dev/docs/navpatterns/patterns/notifications/index.xml" rel="self" type="application/rss+xml"/><item><title>Docs: In-context Notifications</title><link>https://alguidelines.dev/docs/navpatterns/patterns/notifications/in-context-notifications/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://alguidelines.dev/docs/navpatterns/patterns/notifications/in-context-notifications/</guid><description>
|
||
<p><em>By Soumya Dutta at Microsoft Development Center Copenhagen</em></p>
|
||
<h2 id="context">Context</h2>
|
||
<p>Application developers need to raise a notification on events that are not blocking but do require attention from users. Notifications alert users to issues or information, and let them decide whether to react immediately or finish what they&rsquo;re doing first.</p>
|
||
<h2 id="problem">Problem</h2>
|
||
<p>Application developers have started to use system calls like CONFIRM or MESSAGE to alert or inform users about a condition. These calls interrupt users by displaying a window in the middle of the screen and forcing an immediate response.</p>
|
||
<h2 id="solution">Solution</h2>
|
||
<p>Notifications display a message in a blue bar at the top of the workspace, as shown in Figure 1.</p>
|
||
<p><a href="7701.Fig1.png"><img src="7701.Fig1.png" alt=" "></a></p>
|
||
<p>Figure 1 - Example of a notification</p>
|
||
<p>Notifications alert users to something they probably should act on, but can choose to ignore. For example, a notification might alert someone who is about to invoice a customer for inventory that isn&rsquo;t available, as shown in Figure 1, but allow them to post the invoice anyway. This is different from an error that prevents someone from posting an invoice without specifying a required field.</p>
|
||
<p>In this example, if you choose <strong>Details</strong> a page opens to show the status of the inventory, as shown in Figure 2.</p>
|
||
<p><a href="6724.Fig2.png"><img src="6724.Fig2.png" alt=" "></a></p>
|
||
<p>Figure 2 - Clicking an action in a notification</p>
|
||
<h2 id="raising-a-notification">Raising a notification</h2>
|
||
<p>The code in Figure 3 raises the notification in Figure 1.</p>
|
||
<p><strong>COD 311: Item-Check Avail.</strong></p>
|
||
<p><strong>CreateAndSendNotification</strong></p>
|
||
<p>AvailabilityCheckNotification.ID(GetItemAvailabilityNotificationId);</p>
|
||
<p>AvailabilityCheckNotification.MESSAGE(STRSUBSTNO(NotificationMsg,ItemNo));</p>
|
||
<p>AvailabilityCheckNotification.SCOPE(NOTIFICATIONSCOPE::LocalScope);</p>
|
||
<p>AvailabilityCheckNotification.ADDACTION(DetailsTxt,CODEUNIT::&ldquo;Item-Check Avail.&rdquo;,&lsquo;ShowNotificationDetails&rsquo;);</p>
|
||
<p>ItemAvailabilityCheck.PopulateDataOnNotification(AvailabilityCheckNotification,ItemNo,UnitOfMeasureCode</p>
|
||
<p>,InventoryQty,GrossReq,ReservedReq,SchedRcpt,ReservedRcpt,CurrentQuantity,CurrentReservedQty,</p>
|
||
<p>TotalQuantity,EarliestAvailDate);</p>
|
||
<p>AvailabilityCheckNotification.SEND;</p>
|
||
<p>&hellip;</p>
|
||
<p>Figure 3 - Raising a notification</p>
|
||
<p>The first thing to note is that a new Notification DataType object has been introduced to C/SIDE.</p>
|
||
<p><a href="2514.Fig4.png"><img src="2514.Fig4.png" alt=" "></a></p>
|
||
<p>Figure 4. Notification is a new data type</p>
|
||
<p>In the code sample in Figure 3, the first line defines the scope. Currently , only the LocalScope is supported.</p>
|
||
<h3 id="identifying-a-notification">Identifying a notification</h3>
|
||
<p>The ID is an optional parameter for the notification object that tracks the object in communications between the client and the server. Notifications have unique IDs that can be hard coded as GUIDs, as shown in Figure 5. A GUID can be generated using <a href="https://msdn.microsoft.com/en-us/library/dd339033.aspx">the CREATEGUID system function</a>.</p>
|
||
<p><strong>COD 311: Item-Check Avail.</strong></p>
|
||
<p><strong>GetItemAvailabilityNotificationId</strong></p>
|
||
<p>EXIT(&lsquo;2712AD06-C48B-4C20-820E-347A60C9AD00&rsquo;);</p>
|
||
<p>Figure 5. Uniquely identifying a notification</p>
|
||
<p>If the call to set ID is skipped, sending the notification creates a new notification with an ID that is generated at run-time instead of updating a notification that is already displayed (if present) with the ID.</p>
|
||
<h3 id="including-messages-notifications">Including messages notifications</h3>
|
||
<p>Notifications should display a message. This message is set by an assignment call to the <strong>MESSAGE</strong> parameter of the notification object.</p>
|
||
<h3 id="invoking-actions-on-notifications">Invoking actions on notifications</h3>
|
||
<p>Notifications can display action buttons, as shown in Figure 2 where a button named <strong>Details</strong> opens the inventory status for the item. To do that, when the button is clicked the <strong>ADDACTION</strong> method is invoked on the notification object using the following parameters:</p>
|
||
<ul>
|
||
<li>The text for the button.</li>
|
||
<li>The code unit number that hosts the method to call.</li>
|
||
<li>The name of the invoked method in the above code unit to call.</li>
|
||
</ul>
|
||
<p>Figure shows the method that is called when the action is invoked- ShowNotificationDetails.</p>
|
||
<p><strong>COD 311: Item-Check Avail.</strong></p>
|
||
<p><strong>ShowNotificationDetails</strong></p>
|
||
<p>ItemAvailabilityCheck.InitializeFromNotification(AvailabilityCheckNotification);</p>
|
||
<p>ItemAvailabilityCheck.SetHeading(AvailabilityCheckNotification.MESSAGE);</p>
|
||
<p>ItemAvailabilityCheck.RUNMODAL;****</p>
|
||
<p>Figure 6 - Invoking an action</p>
|
||
<p>To show the inventory status using the Availability check page, certain parameters must be initialized. For example, the item number, the unit of measure code, and so on. This is done in the call to InitializeFromNotification method on the page. Figure 7 shows the code for this call.</p>
|
||
<p><strong>Page 1872: Item Availability Check</strong></p>
|
||
<p><strong>InitializeFromNotification</strong></p>
|
||
<p>GET(AvailabilityCheckNotification.GETDATA(&lsquo;ItemNo&rsquo;));</p>
|
||
<p>SETRANGE(&ldquo;No.&quot;,AvailabilityCheckNotification.GETDATA(&lsquo;ItemNo&rsquo;));</p>
|
||
<p>EVALUATE(TotalQuantity,AvailabilityCheckNotification.GETDATA(&lsquo;TotalQuantity&rsquo;));</p>
|
||
<p>EVALUATE(InventoryQty,AvailabilityCheckNotification.GETDATA(&lsquo;InventoryQty&rsquo;));</p>
|
||
<p>CurrPage.AvailabilityCheckDetails.PAGE.SetUnitOfMeasureCode(</p>
|
||
<p>AvailabilityCheckNotification.GETDATA(&lsquo;UnitOfMeasureCode&rsquo;));</p>
|
||
<p>Figure 7 - Fetching parameters from a notification object</p>
|
||
<p>Note how <strong>GETDATA</strong> uses a key to fetch values from the notification object, and how those values are used to initialize the page.</p>
|
||
<p>Notifications can include zero, one, or more than one action buttons. More than one action buttons result in multiple <strong>ADDACTION</strong> calls to the notification object.</p>
|
||
<h3 id="populating-parameters-on-notifications">Populating parameters on notifications</h3>
|
||
<p>Actions use the values set on the notification objects. As shown in Figure 3 and Figure 7, the line that calls the method PopulateDataOnNotification does that. The result is shown in Figure 8.</p>
|
||
<p><strong>Page 1872: Item Availability Check</strong></p>
|
||
<p><strong>PopulateDataOnNotification</strong></p>
|
||
<p>AvailabilityCheckNotification.SETDATA(&lsquo;ItemNo&rsquo;,ItemNo);</p>
|
||
<p>AvailabilityCheckNotification.SETDATA(&lsquo;UnitOfMeasureCode&rsquo;,UnitOfMeasureCode);</p>
|
||
<p>AvailabilityCheckNotification.SETDATA(&lsquo;GrossReq&rsquo;,FORMAT(GrossReq));</p>
|
||
<p>&hellip;</p>
|
||
<p>Figure 8 - Populating parameters on notifications</p>
|
||
<p>The invoked method must be stateless. Therefore, the context for creating the notification should be reproducible by using data that could be a part of the notification object. In this example, the SETDATA method on the notification object passes values for the item number, unit of measure code, and so on, as key value pairs.</p>
|
||
<h3 id="displaying-the-notification-to-the-user">Displaying the notification to the user</h3>
|
||
<p>The last line in Figure 3 calls <strong>SEND</strong> to display the notification. If you know the ID of the notification, you can also call <strong>RECALL</strong> to hide it. However, avoid updating a displayed notification, for example by changing the message, by calling both <strong>RECALL</strong> and <strong>SEND</strong>. This makes two server&ndash;client calls. Instead, call only <strong>SEND</strong>. Calling <strong>SEND</strong> for a notification that is already displayed updates the notification.</p>
|
||
<h2 id="turning-notifications-on-or-off-and-controlling-when-they-are-sent">Turning notifications on or off, and controlling when they are sent</h2>
|
||
<p>By default, all notifications are turned on. However, you can specify the notifications you want to receive, and turn on or turn off some or all of them. For example, if you don&rsquo;t want to be disturbed or are willing to accept the consequences of ignoring the message. This is unique to notifications.</p>
|
||
<p><a href="6646.Fig9.png"><img src="6646.Fig9.png" alt=" "></a></p>
|
||
<p>Figure 9 - The My Notifications page</p>
|
||
<p>Additionally, some notifications let you specify the conditions under which they are sent. For example, if you want to be notified when inventory is running low, but only for items you buy from a certain vendor.</p>
|
||
<ol>
|
||
<li>In the top right corner, choose the Search for Page or Report icon, enter my notifications, and then choose the related link.</li>
|
||
<li>To turn on or turn off a notification, select or clear the Enabled check box.</li>
|
||
<li>To specify conditions that trigger a notification, choose View filter details, and then fill in the fields.</li>
|
||
</ol>
|
||
<p>The <strong>MyNotifications</strong> object determines whether notifications are turned on or off. Notifications are isolated from each other by the hard-coded GUID, as discussed in the section titled Identifying a notification. A fixed ID is essential to turning off a notification. The following are ways to achieve this.</p>
|
||
<ol>
|
||
<li><strong>OnInitializingNotificationWithDefaultState</strong> is a published method on the <strong>MyNotifications</strong> page that is called when the enabled state of all the notifications is initialized.</li>
|
||
</ol>
|
||
<p><strong>Codeunit 311: Item-Check Avail.</strong></p>
|
||
<p><strong>OnInitializingNotificationWithDefaultState</strong></p>
|
||
<p>MyNotifications.InsertDefaultWithTableNum(GetItemAvailabilityNotificationId,</p>
|
||
<p>ItemAvailabilityNotificationTxt,</p>
|
||
<p>ItemAvailabilityNotificationDescriptionTxt,</p>
|
||
<p>DATABASE::Item);</p>
|
||
<p>Figure 10 - Adding a notification to the My Notifications page</p>
|
||
<p>You must subscribe to this method and call either <strong>InsertDefault</strong> or <strong>InsertDefaultWithTableNum</strong> on the <strong>MyNotifications</strong> table. Both of these take the ID of the notification, a short description of the notification, and text that provides details about the conditions for the notification. The difference is that the <strong>InsertDefaultWithTableNum</strong> method takes an additional argument representing the table number if there is specific criteria for when to turn on a notification for a certain table. In this case, the notification can be enabled only for items that the criteria specified in the FilterPage. The FIlterPage is opened from the <strong>MyNotifications</strong> page.</p>
|
||
<p><a href="2526.Fig11.png"><img src="2526.Fig11.png" alt=" "></a></p>
|
||
<p>Figure 11 - Defining filter criteria to turn on a notification</p>
|
||
<ol>
|
||
<li><strong>IsEnabled</strong> or <strong>IsEnabledForRecord</strong> are used to query if the notification is turned on. It may make sense to call this as early as possible in the condition checks, so you don&rsquo;t make calculations that will not yield much if the notification is turned off. The second method takes the additional parameter that represents the record for which the enabled state is to be determined. In Figure 12, the check is for an item.</li>
|
||
</ol>
|
||
<p><strong>Codeunit 311: Item-Check Avail.</strong></p>
|
||
<p><strong>IsItemAvailabilityNotificationEnabled</strong></p>
|
||
<p><strong>EXIT</strong>(MyNotifications.IsEnabledForRecord(GetItemAvailabilityNotificationId,Item));</p>
|
||
<p>Figure 12 - Checking whether notifications are turned on</p>
|
||
<p>You may check that the call to this function is made almost as the first step in checking for availability.</p>
|
||
<ol>
|
||
<li><strong>OnStateChanged</strong> event should be subscribed to if the developer needs to do something additional when changing the state of a notification, such as turn on another notification.</li>
|
||
</ol>
|
||
<p>The ability to turn notifications on or off is not required. If skipped, the notification is always shown when the condition that triggers it is met, and a user cannot turn it off.</p>
|
||
<h2 id="nav-specific-usages">NAV specific usages</h2>
|
||
<p>For examples of how these objects are used in Dynamics NAV, look at the code for the following objects:</p>
|
||
<ol>
|
||
<li>Codeunit 1802 Data Migration Notifier</li>
|
||
<li>Codeunit 311 Item-Check Avail.</li>
|
||
<li>Codeunit 312 Cust-Check Cr. Limit</li>
|
||
<li>Codeunit 1854 Item Sales Forecast Notifier (in SalesAndInventoryForecast extension)</li>
|
||
<li>Codeunit 1852 Item Sales Forecast Scheduler (in SalesAndInventoryForecast extension)</li>
|
||
</ol>
|
||
<h2 id="best-practices">Best practices</h2>
|
||
<p>The following list summarizes best practices for creating notifications:</p>
|
||
<ol>
|
||
<li>Do not set data on the notification that you will not use in the method invoked from the action button.</li>
|
||
<li>Ensure that the <strong>MyNotifications</strong> table is accessed only as described above, and that the correct pairs of calls are made. For example, <strong>InsertDefault</strong>&hellip;<strong>IsEnabled</strong> and <strong>InsertDefaultWithTableNum</strong> &hellip;<strong>IsEnabledForRecord</strong>.</li>
|
||
<li>Do not call <strong>RECALL</strong> before <strong>SEND</strong> in a server call-back if you need to update a notification that is already displayed. Instead, call only <strong>SEND</strong> to update the notification. This reduces traffic on the network.</li>
|
||
<li>Ensure that the method specified on the <strong>ADDACTION</strong> method for the notification is (a) exists, (b) is global and (c) follows the signature described above.</li>
|
||
</ol></description></item><item><title>Docs: Notification Lifecycle Management Pattern</title><link>https://alguidelines.dev/docs/navpatterns/patterns/notifications/notification-lifecycle-management-pattern/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://alguidelines.dev/docs/navpatterns/patterns/notifications/notification-lifecycle-management-pattern/</guid><description>
|
||
<p><em>By David Bastide at Microsoft Development Center Copenhagen</em></p>
|
||
<p><a href="6138.logo.png"><img src="6138.logo.png" alt=" "></a></p>
|
||
<p> </p>
|
||
<p><strong>Context</strong></p>
|
||
<p>This pattern is about sending notifications in Dynamics NAV, starting with version 2018, tracking them in the Notification Lifecycle Management framework, and recalling them when needed.</p>
|
||
<p> </p>
|
||
<p><strong>Description</strong></p>
|
||
<p>Notifications are easy to use in a wide range of cases. Instead of using notifications in a fire-and-forget way, we need to track them so that we can recall them if we need to.</p>
|
||
<p>If we can have only one notification on a given page, an easy and efficient solution is to use a predefined Notification ID, as suggested in the <a href="https://alguidelines.dev/navpatterns/1-patterns/notifications/in-context-notifications/">&ldquo;Using In-context Notifications&rdquo;</a> pattern.</p>
|
||
<p>However, some cases can be more complicated. For example, when you are adding lines to a table, what if several lines raise individual notifications? Using the same notification ID for each notification will no longer work because the latest notification overwrites the previous ones. Only one notification for a given notification ID can exist, and only the notification message would be updated. This is illustrated in Figure 1.</p>
|
||
<p><a href="4807.1st-notification.PNG"><img src="4807.1st-notification.PNG" alt=" "></a></p>
|
||
<p><em>Figure 1: Notification that an item that is not in stock. The notification ID is a predefined GUID, 2712AD06-C48B-4C20-820E-347A60C9AD00, for example.</em></p>
|
||
<p><a href="8512.2nd-notification.PNG"><img src="8512.2nd-notification.PNG" alt=" "></a></p>
|
||
<p><em>Figure 2: You add a second item that is not in stock. the notification is fired with the same GUID, 2712AD06-C48B-4C20-820E-347A60C9AD00, for example. The previous notification is overwritten.</em></p>
|
||
<p>Here is the code for this behavior:</p>
|
||
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-al" data-lang="al"><span style="color:#204a87;font-weight:bold">LOCAL</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">PROCEDURE</span><span style="color:#f8f8f8;text-decoration:underline"> </span>CreateAndSendNotification@<span style="color:#0000cf;font-weight:bold">23</span><span style="color:#ce5c00;font-weight:bold">(</span>UnitOfMeasureCode@<span style="color:#0000cf;font-weight:bold">1010</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Code</span>[<span style="color:#0000cf;font-weight:bold">20</span>]<span style="color:#000;font-weight:bold">;</span>InventoryQty@<span style="color:#0000cf;font-weight:bold">1009</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>GrossReq@<span style="color:#0000cf;font-weight:bold">1008</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>ReservedReq@<span style="color:#0000cf;font-weight:bold">1007</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>SchedRcpt@<span style="color:#0000cf;font-weight:bold">1006</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>ReservedRcpt@<span style="color:#0000cf;font-weight:bold">1005</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>CurrentQuantity@<span style="color:#0000cf;font-weight:bold">1004</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>CurrentReservedQty@<span style="color:#0000cf;font-weight:bold">1003</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>TotalQuantity@<span style="color:#0000cf;font-weight:bold">1002</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>EarliestAvailDate@<span style="color:#0000cf;font-weight:bold">1001</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Date</span><span style="color:#ce5c00;font-weight:bold">) </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Boolean</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">VAR</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>ItemAvailabilityCheck@<span style="color:#0000cf;font-weight:bold">1011</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Page</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">1872</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification@<span style="color:#0000cf;font-weight:bold">1000</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Notification</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">BEGIN</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>ID<span style="color:#ce5c00;font-weight:bold">(</span>GetItemAvailabilityNotificationId<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>MESSAGE<span style="color:#ce5c00;font-weight:bold">(</span>STRSUBSTNO<span style="color:#ce5c00;font-weight:bold">(</span>NotificationMsg<span style="color:#000;font-weight:bold">,</span>ItemNo<span style="color:#ce5c00;font-weight:bold">))</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>SCOPE<span style="color:#ce5c00;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">NOTIFICATIONSCOPE</span><span style="color:#000;font-weight:bold">::</span>LocalScope<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>ADDACTION<span style="color:#ce5c00;font-weight:bold">(</span>DetailsTxt<span style="color:#000;font-weight:bold">,</span><span style="color:#204a87;font-weight:bold">CODEUNIT</span><span style="color:#000;font-weight:bold">::</span>&#34;Item-Check Avail.&#34;<span style="color:#000;font-weight:bold">,</span><span style="color:#4e9a06">&#39;ShowNotificationDetails&#39;</span><span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>ItemAvailabilityCheck<span style="color:#ce5c00;font-weight:bold">.</span>PopulateDataOnNotification<span style="color:#ce5c00;font-weight:bold">(</span>AvailabilityCheckNotification<span style="color:#000;font-weight:bold">,</span>ItemNo<span style="color:#000;font-weight:bold">,</span>UnitOfMeasureCode<span style="color:#000;font-weight:bold">,</span>InventoryQty<span style="color:#000;font-weight:bold">,</span>GrossReq<span style="color:#000;font-weight:bold">,</span>ReservedReq<span style="color:#000;font-weight:bold">,</span>SchedRcpt<span style="color:#000;font-weight:bold">,</span>ReservedRcpt<span style="color:#000;font-weight:bold">,</span>CurrentQuantity<span style="color:#000;font-weight:bold">,</span>CurrentReservedQty<span style="color:#000;font-weight:bold">,</span>TotalQuantity<span style="color:#000;font-weight:bold">,</span>EarliestAvailDate<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>SEND<span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">EXIT</span><span style="color:#ce5c00;font-weight:bold">(</span>FALSE<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">END</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">LOCAL</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">PROCEDURE</span><span style="color:#f8f8f8;text-decoration:underline"> </span>**GetItemAvailabilityNotificationId**@<span style="color:#0000cf;font-weight:bold">27</span><span style="color:#ce5c00;font-weight:bold">() </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">GUID</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">BEGIN</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">EXIT</span><span style="color:#ce5c00;font-weight:bold">(</span><span style="color:#4e9a06">&#39;2712AD06-C48B-4C20-820E-347A60C9AD00&#39;</span><span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">END</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span></code></pre></div><p>An easy fix would be to dynamically generate the notification ID. However, what if you fix the issue that triggered the notification?</p>
|
||
<p>Here is the code for this possible fix:</p>
|
||
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-al" data-lang="al"><span style="color:#204a87;font-weight:bold">LOCAL</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">PROCEDURE</span><span style="color:#f8f8f8;text-decoration:underline"> </span>CreateAndSendNotification@<span style="color:#0000cf;font-weight:bold">23</span><span style="color:#ce5c00;font-weight:bold">(</span>UnitOfMeasureCode@<span style="color:#0000cf;font-weight:bold">1010</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Code</span>[<span style="color:#0000cf;font-weight:bold">20</span>]<span style="color:#000;font-weight:bold">;</span>InventoryQty@<span style="color:#0000cf;font-weight:bold">1009</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>GrossReq@<span style="color:#0000cf;font-weight:bold">1008</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>ReservedReq@<span style="color:#0000cf;font-weight:bold">1007</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>SchedRcpt@<span style="color:#0000cf;font-weight:bold">1006</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>ReservedRcpt@<span style="color:#0000cf;font-weight:bold">1005</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>CurrentQuantity@<span style="color:#0000cf;font-weight:bold">1004</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>CurrentReservedQty@<span style="color:#0000cf;font-weight:bold">1003</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>TotalQuantity@<span style="color:#0000cf;font-weight:bold">1002</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Decimal</span><span style="color:#000;font-weight:bold">;</span>EarliestAvailDate@<span style="color:#0000cf;font-weight:bold">1001</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Date</span><span style="color:#ce5c00;font-weight:bold">) </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Boolean</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">VAR</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>ItemAvailabilityCheck@<span style="color:#0000cf;font-weight:bold">1011</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Page</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">1872</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification@<span style="color:#0000cf;font-weight:bold">1000</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">Notification</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">BEGIN</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>ID<span style="color:#ce5c00;font-weight:bold">(</span>CREATEGUID<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>MESSAGE<span style="color:#ce5c00;font-weight:bold">(</span>STRSUBSTNO<span style="color:#ce5c00;font-weight:bold">(</span>NotificationMsg<span style="color:#000;font-weight:bold">,</span>ItemNo<span style="color:#ce5c00;font-weight:bold">))</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>SCOPE<span style="color:#ce5c00;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">NOTIFICATIONSCOPE</span><span style="color:#000;font-weight:bold">::</span>LocalScope<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>ADDACTION<span style="color:#ce5c00;font-weight:bold">(</span>DetailsTxt<span style="color:#000;font-weight:bold">,</span><span style="color:#204a87;font-weight:bold">CODEUNIT</span><span style="color:#000;font-weight:bold">::</span>&#34;Item-Check Avail.&#34;<span style="color:#000;font-weight:bold">,</span><span style="color:#4e9a06">&#39;ShowNotificationDetails&#39;</span><span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>ItemAvailabilityCheck<span style="color:#ce5c00;font-weight:bold">.</span>PopulateDataOnNotification<span style="color:#ce5c00;font-weight:bold">(</span>AvailabilityCheckNotification<span style="color:#000;font-weight:bold">,</span>ItemNo<span style="color:#000;font-weight:bold">,</span>UnitOfMeasureCode<span style="color:#000;font-weight:bold">,</span>InventoryQty<span style="color:#000;font-weight:bold">,</span>GrossReq<span style="color:#000;font-weight:bold">,</span>ReservedReq<span style="color:#000;font-weight:bold">,</span>SchedRcpt<span style="color:#000;font-weight:bold">,</span>ReservedRcpt<span style="color:#000;font-weight:bold">,</span>CurrentQuantity<span style="color:#000;font-weight:bold">,</span>CurrentReservedQty<span style="color:#000;font-weight:bold">,</span>TotalQuantity<span style="color:#000;font-weight:bold">,</span>EarliestAvailDate<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>AvailabilityCheckNotification<span style="color:#ce5c00;font-weight:bold">.</span>SEND<span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">EXIT</span><span style="color:#ce5c00;font-weight:bold">(</span>FALSE<span style="color:#ce5c00;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">END</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
|
||
</span></code></pre></div><p>Now, notifications do not replace each other, but we cannot recall them because we do not track each notification ID.</p>
|
||
<p><a href="0677.3-notifications-smaller.PNG"><img src="0677.3-notifications-smaller.PNG" alt=" "></a></p>
|
||
<p><em>Figure 3: Three sales lines with a notification for each one</em></p>
|
||
<p>Imagine that you&rsquo;re adding several items to a sales order, and inventory is low for some of the items. Each sales line will send a notification for its item if the quantity to sell is higher than the available inventory. By using dynamically generated notification IDs (<strong>CREATEGUID</strong>), each notification will not be overwritten, which is what we want. This is shown in Figure 3. But after you see the notification, you may decide to decrease the quantity in the sales line. At that point, the notification should be recalled. To do that, we need a way to track the notifications and their IDs.</p>
|
||
<p> </p>
|
||
<p><strong>Solution</strong></p>
|
||
<p>The solution is to use the Notification Lifecycle Management framework.</p>
|
||
<p>The framework allows you to keep track of notifications by saving notification IDs and with other useful information (record ID and optional additional context) that will allow you to easily find the notification IDs to recall. This can be seen as an internal dictionary to put and get notification IDs.</p>
|
||
<p> </p>
|
||
<p>This framework has three main components:</p>
|
||
<ul>
|
||
<li>
|
||
<p>A temporary, in-memory table: <strong>Notification Context</strong> (1519). This table stores each notification GUID, the record ID of the record that caused each notification (on what object), and optionally, an additional GUID that represents an additional context: the cause of the notification (why). This lets you track and recall each notification. You can fire-and-forget the notification, but if you need to recall it you can find it by using the record ID of the cause and the optional additional context ID.</p>
|
||
</li>
|
||
<li>
|
||
<p>A singleton codeunit: <strong>Notification Lifecycle Mgt.</strong> (1511), that provides functions to create new notification context lines and recall them. This codeunit contains one instance of the temporary table <strong>Notification Context</strong>.</p>
|
||
</li>
|
||
<li>
|
||
<p>A helper codeunit:<strong>Notification Lifecycle Helper</strong> (1508), that subscribes to various events and makes the calls to the <strong>Notification Lifecycle Mgt.</strong> codeunit.</p>
|
||
</li>
|
||
</ul>
|
||
<p> </p>
|
||
<p>The unit tests for this framework are in codeunit <strong>Notification Lifecycle Tests</strong> (139480).</p>
|
||
<p> </p>
|
||
<p>The main functions provided by codeunit 1511 are:</p>
|
||
<ul>
|
||
<li>
|
||
<p><strong>SendNotification</strong>(NotificationToSend : Notification;RecId : RecordID)</p>
|
||
<ul>
|
||
<li>Sends a notification and keeps track of it in the simplest way. We have a notification to send and the record ID of the object that triggered the notification.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>SendNotificationWithAdditionalContext</strong>(NotificationToSend : Notification;RecId : RecordID;AdditionalContextId : GUID)</p>
|
||
<ul>
|
||
<li>Sends a notification and keeps track of it with additional information. For example, a GUID that represents the context in which the notification was sent, and an item with insufficient inventory.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>RecallNotificationsForRecord</strong>(RecId : RecordID;HandleDelayedInsert : Boolean)</p>
|
||
<ul>
|
||
<li>Recalls all notifications that were sent by a given record ID. The HandleDelayedInsert flag should be TRUE if it is possible that the record ID provided is from a record that was not yet in the database (TRUE unless we recall notifications after deletion of a record).</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>RecallNotificationsForRecordWithAdditionalContext</strong>(RecId : RecordID;AdditionalContextId : GUID;HandleDelayedInsert : Boolean)</p>
|
||
<ul>
|
||
<li>Recalls the notification that was sent by a given Record ID in a particular context. The HandleDelayedInsert flag should be TRUE if it is possible that the Record ID provided is from a record that was not yet in the database (TRUE unless we recall notifications after deleting a record).</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>SetRecordID</strong>(RecId : RecordID)</p>
|
||
<ul>
|
||
<li>Sets the record ID after delayed insertion of a record. This will update the initially incomplete Record ID in the <strong>Notification Context</strong> table to a full Record ID.</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>UpdateRecordID</strong>(CurrentRecId : RecordID;NewRecId : RecordID)</p>
|
||
<ul>
|
||
<li>Replace CurrentRecId with NewRecId in the <strong>Notification Context</strong> table. This is called by <strong>SetRecordId</strong>.</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p> </p>
|
||
<p><strong>Usage</strong></p>
|
||
<p> </p>
|
||
<p>The simple case is:</p>
|
||
<ol>
|
||
<li>We create a notification object.</li>
|
||
<li>We call <strong>SendNotification</strong> or <strong>SendNotificationWithAdditionalContext</strong>.</li>
|
||
<li>When we want to recall the notification, we call <strong>RecallNotificationsForRecord</strong> or <strong>RecallNotificationsForRecordWithAdditionalContext</strong>.</li>
|
||
</ol>
|
||
<p><a href="sequence1.png"><img src="sequence1.png" alt=" "></a></p>
|
||
<p><em>Figure 4: without additional context</em></p>
|
||
<p><a href="sequence2.png"><img src="sequence2.png" alt=" "></a></p>
|
||
<p><em>Figure 5: with additional context</em></p>
|
||
<p>However, delayed insert means that the simple case seen above doesn&rsquo;t happen very often. The issue is that when we call <strong>SendNotification</strong>, we provide the cause object&rsquo;s record ID. If this object has not been inserted yet, which is often the case when the user creates a new invoice, a new line, and so on, the record ID is incomplete. When the object is inserted the record ID is completed, but if we call <strong>RecallNotificationsForRecord</strong> at a later point, the record ID will be different from the incomplete record ID we used when sending the notification. The solution is to detect that the object is not yet inserted when we send the notification, and at a later point, set the record ID when the cause object is inserted. </p>
|
||
<p> </p>
|
||
<p>The realistic case is:</p>
|
||
<ol>
|
||
<li>We have a temporary object with a partially complete ID. Something like: Sales Line, 1000, &ldquo;&rdquo;.</li>
|
||
<li>We send a notification caused by this object (item out of stock).</li>
|
||
<li>The temporary table receives NotificationId, empty record Id (Quote, &ldquo;&quot;), additional context (item out of stock).</li>
|
||
<li>When the user leaves the field, the line is inserted. We replace the empty record ID (Quote, &ldquo;&quot;) by the full record ID (Sales Line, 1000, 10000).</li>
|
||
<li>We recall the notification (the user put a lower quantity for example).</li>
|
||
<li>We search for records with the full record ID and the additional context (item out of stock).</li>
|
||
<li>If found, they are recalled. </li>
|
||
</ol>
|
||
<p><a href="sequence3.png"><img src="sequence3.png" alt=" "></a></p>
|
||
<p><em>Figure 6: delayed insert, with additional context</em></p>
|
||
<p><strong>Usages in NAV:</strong></p>
|
||
<p>COD311 (Item-Check Avail.)</p>
|
||
<p>COD312 (Cust-Check Cr. Limit)</p>
|
||
<p>COD1508 (Notification Lifecycle Handler)</p>
|
||
<p><strong>Related Patterns:</strong></p>
|
||
<p><a href="https://alguidelines.dev/navpatterns/1-patterns/notifications/in-context-notifications/">In-context notifications</a></p>
|
||
<p><a href="https://alguidelines.dev/navpatterns/1-patterns/singleton/singleton-codeunit/">Singleton codeunit</a></p></description></item></channel></rss> |