This commit is contained in:
JeremyVyska 2022-02-20 20:13:18 +00:00
parent 34af3362da
commit 2d866c6316
732 changed files with 136202 additions and 67025 deletions

View file

@ -0,0 +1,67 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>alguidelines.dev - Business Central Design Patterns Blocked Entity</title><link>https://alguidelines.dev/docs/navpatterns/patterns/blocked-entity/</link><description>Recent content in Blocked Entity 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/blocked-entity/index.xml" rel="self" type="application/rss+xml"/><item><title>Docs: Data Driven Blocked Entity</title><link>https://alguidelines.dev/docs/navpatterns/patterns/blocked-entity/data-driven-blocked-entity/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://alguidelines.dev/docs/navpatterns/patterns/blocked-entity/data-driven-blocked-entity/</guid><description>
&lt;p>&lt;em>Written by Bogdan Andrei Sturzoiu, at Microsoft Development Center Copenhagen&lt;/em>&lt;/p>
&lt;h2 id="abstract">Abstract&lt;/h2>
&lt;p>This pattern implements a generic mechanism for dynamically restricting and allowing usage of a record by the business process administrator.&lt;/p>
&lt;h2 id="problem">Problem&lt;/h2>
&lt;p>A NAV record can be used in a number of functionalities across the app. There are situations, however, when the administrator wants to restrict the consumption of such a record, as well as lift the restriction when it is no longer relevant.&lt;/p>
&lt;p>For example, a new customer record should not be used for posting documents until it is approved by the relevant approver.&lt;/p>
&lt;p>We could solve this by using the &lt;a href="https://alguidelines.dev/navpatterns/1-patterns/blocked-entity/">Blocked Entity pattern&lt;/a>, but it requires database schema changes, which have an upgrade impact.&lt;/p>
&lt;p>The blocked entity pattern involves:&lt;/p>
&lt;ol>
&lt;li>Adding a &amp;ldquo;blocked&amp;rdquo; status field on the record (either a Boolean or in the more advanced cases, an option field refining the usage).&lt;/li>
&lt;li>Adding specific code for the record in every place where the restriction needs to be enforced.&lt;/li>
&lt;/ol>
&lt;p>In contrast, the Data-driven Blocked Entity pattern involves adding a new record (data change) to mark the restriction, instead of adding a new field (metadata change).&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;p>This pattern describes a generic mechanism of adding and lifting restrictions for any type of record.&lt;/p>
&lt;p>The restriction mechanism has the following elements:&lt;/p>
&lt;ol>
&lt;li>Adding a restriction record for a specific reason (e.g. the record requires approval), which will act as a surrogate key (unique identifier) for the restricted record. This can be implemented through a workflow response, or directly, by calling the Restriction Management codeunit function.&lt;/li>
&lt;li>Lifting the restriction when it is no longer necessary. Again, this can be done using a workflow response or directly by calling the dedicated function.&lt;/li>
&lt;li>Consuming the restriction in the places of interest for a specific purpose. This is an application feature that requires a call to the Restriction Management codeunit to check for restrictions.&lt;/li>
&lt;/ol>
&lt;p>Currently, the restrictions are record-based and type-less. They act as simple tokens, and they have:&lt;/p>
&lt;ul>
&lt;li>A reason (e.g. the record requires approval)&lt;/li>
&lt;li>A purpose (e.g. the record cannot be posted).&lt;/li>
&lt;/ul>
&lt;p>You must make sure to differentiate between the reason and the purpose. That is because the restriction can only be added once per record, but consumed in multiple places.&lt;/p>
&lt;h2 id="example">Example&lt;/h2>
&lt;p>For example, we want to restrict posting Gen. Journal Lines if a customer has not been added in Account No. field.&lt;/p>
&lt;p>For this, the following components are needed:&lt;/p>
&lt;ol>
&lt;li>When a Gen. Journal Line is inserted, call RestrictRecordUsage in COD1550, either directly in the trigger or using an event subscriber.&lt;/li>
&lt;li>When you validate a Customer No. as Account no. and Customer as Account Type, lift the restrictions by calling AllowRecordUsage in COD1550.&lt;/li>
&lt;li>The consumption of the restriction at posting is already implemented as an event in TAB81, OnCheckGenJournalLinePostRestrictions. No further action necessary.&lt;/li>
&lt;/ol>
&lt;h2 id="nav-usage">NAV Usage&lt;/h2>
&lt;p>All the approval workflows include a response that restricts usage of a record, and then, at the end of an approval loop, a response that allows the usage again by lifting the restriction. See responses &amp;ldquo;Add record restriction&amp;rdquo; and &amp;ldquo;Remove record restriction&amp;rdquo; implemented in COD1521.&lt;a href="https://microsoft.sharepoint.com/teams/DynamicsNAV/Wiki/Nav%20Wiki%20Documents/NAV%20App%20Patterns/NAV%20App%20Patterns%20for%20Review/Data-Driven%20Blocked%20Entity.docx#_msocom_2">&lt;br>
&lt;/a>&lt;/p>
&lt;p>The code behind the &amp;ldquo;Add record restriction&amp;rdquo; workflow response:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-AL" data-lang="AL">RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>GETTABLE&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">Variant&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>Workflow&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>GET&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>WorkflowStepInstance&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&amp;#34;Workflow Code&amp;#34;&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>RecordRestrictionMgt&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>RestrictRecordUsage&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#204a87;font-weight:bold">RECORDID&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>STRSUBSTNO&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>RestrictUsageDetailsTxt&lt;span style="color:#000;font-weight:bold">,&lt;/span>Workflow&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#204a87;font-weight:bold">Code&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>Workflow&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>Description&lt;span style="color:#ce5c00;font-weight:bold">))&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The code behind the &amp;ldquo;Remove record restriction&amp;rdquo; response:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-AL" data-lang="AL">RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>GETTABLE&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">Variant&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">CASE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>NUMBER&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">OF&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">DATABASE&lt;/span>&lt;span style="color:#000;font-weight:bold">::&lt;/span>&amp;#34;Approval Entry&amp;#34;&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">BEGIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>RecordRestrictionMgt&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>AllowRecordUsage&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#204a87;font-weight:bold">RECORDID&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>SETTABLE&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>ApprovalEntry&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>GET&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>ApprovalEntry&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&amp;#34;Record ID to Approve&amp;#34;&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>AllowRecordUsage&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">END&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">DATABASE&lt;/span>&lt;span style="color:#000;font-weight:bold">::&lt;/span>&amp;#34;Gen. Journal Batch&amp;#34;&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">BEGIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>SETTABLE&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>GenJournalBatch&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>RecordRestrictionMgt&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>AllowGenJournalBatchUsage&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>GenJournalBatch&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">END&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ELSE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>RecordRestrictionMgt&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>AllowRecordUsage&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>RecRef&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#204a87;font-weight:bold">RECORDID&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">END&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Notice how lifting a restriction for a Gen. Journal Batch involves lifting all the restrictions for the individual journal lines in the batch (hence the special branching of the code).&lt;/p>
&lt;h2 id="consequences">Consequences&lt;/h2>
&lt;p>Currently, there can only be one restriction per record. There are no restriction types.&lt;/p>
&lt;p>In the future, a type field should be added to the restriction table, to allow adding restrictions for different purposes, and to refine their consumption. For example, a posting restriction might only be enforced for restrictions originating from approvals.&lt;/p>
&lt;h2 id="nav-versions">NAV Versions&lt;/h2>
&lt;p>This pattern has been introduced in Dynamics NAV 2016.&lt;/p></description></item></channel></rss>