tag:blogger.com,1999:blog-13237784670506067492024-03-13T06:04:16.503-04:00Adventures in Axapta world2020 release wave 2
Installed product version : 10.0.14 (10.0.605.20015)
Installed platform version : Update38 (7.0.5778.41504)wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.comBlogger249125tag:blogger.com,1999:blog-1323778467050606749.post-79904976092467062232024-02-20T17:24:00.006-05:002024-02-21T13:08:23.373-05:00Project intercompany invoice sales tax calculation bug in 10.0.37<p> While Microsoft working on this issue, let me show you how you can fix it in the current code running on 10.0.37 or lower.</p><p><b>Scenario</b></p><p>When using the project intercompany customer invoice form in <i>Project management and accounting</i> module , you can create a customer invoice to bill to an intercompany customer. As the customer is intercompany, there is a legal entity (LE) associated with that customer. When posting the intercompany customer invoice, a pending vendor invoice is created in the customer’s LE with the same lines from the customer invoice.<br /></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhegkyMWKkzQ-rD-iZ3J-Mn3S2pf7X2kIUhjXfEo7bzZrDljarfFsQrGj0eHrsNPv1Y_ZzzhcjLFhkXAJ6AQjTONq1AqqYV2PgotgvJknvVyB_5Buna8x9wsosDdaj1zsOvK0fp3sl4xu2Tzlf9ZO5bc5ko-SoDDBo6Jj2EVSTZZMDKdkofHl4fOxKbn2A/s2517/2024-02-20_17-12-15.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="751" data-original-width="2517" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhegkyMWKkzQ-rD-iZ3J-Mn3S2pf7X2kIUhjXfEo7bzZrDljarfFsQrGj0eHrsNPv1Y_ZzzhcjLFhkXAJ6AQjTONq1AqqYV2PgotgvJknvVyB_5Buna8x9wsosDdaj1zsOvK0fp3sl4xu2Tzlf9ZO5bc5ko-SoDDBo6Jj2EVSTZZMDKdkofHl4fOxKbn2A/s16000/2024-02-20_17-12-15.jpg" /></a></div><br /><p><br /></p><p><br /></p><p>You can see calculated Sales taxes via Sales tax button</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjxdr8SQX5Dz8S6RacYFJ52FRU-XphlUoJo-DCyQ47Ya_ziJuFSWZUWUrPYUVqvffk3QVv027VIJNYlwwsyyfVqVg18ziRqFTSh9ON9cfgiGMeMGd8Rhkh9yhnIaSVubjSgAWUy0l9lhyW4UBcJD3pvc13K2wXVdPNOIGVu4H4vN5KAlzts_M7oqs5j9sE" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="" data-original-height="315" data-original-width="875" height="230" src="https://blogger.googleusercontent.com/img/a/AVvXsEjxdr8SQX5Dz8S6RacYFJ52FRU-XphlUoJo-DCyQ47Ya_ziJuFSWZUWUrPYUVqvffk3QVv027VIJNYlwwsyyfVqVg18ziRqFTSh9ON9cfgiGMeMGd8Rhkh9yhnIaSVubjSgAWUy0l9lhyW4UBcJD3pvc13K2wXVdPNOIGVu4H4vN5KAlzts_M7oqs5j9sE=w640-h230" width="640" /></a></div><br /><br /><p></p><p></p><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /><p></p></div><div><b>Issue</b></div><div><br /></div><div>If you try to add more lines, it will be added with line number 1, and sales taxes won't be added with this newly added line. Note: If you delete any line here and then you add more, it works fine.</div><div><br /></div><div>This bug leads to missed taxes transactions in all <i>TaxUncommitted</i>, <i>TmpTaxWorkTrans</i>, and eventually in <i>TaxTrans </i>tables</div><div><br /></div><div><b>Fix</b></div><div><br /></div><div>Create an extension class with the following code</div><div><br /></div><div><br /></div><div><br /></div><div aria-describedby="bubble-8" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: 4px; opacity: 1; top: 1240px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-8"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowdown" style="left: 15px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(classStr(ProjIntercompanyCustomerInvoiceCreator))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">myProjIntercompanyCustomerInvoiceCreator_Extension</span>
{
<span style="color: #008800; font-weight: bold;">public</span> CustInvoiceTable <span style="color: #0066bb; font-weight: bold;">createInvoice</span>()
{
<span style="color: #888888;">// we need to increase the next line number to avoid duplicates in case when new lines added to initially created ones</span>
lineNum = <span style="color: #008800; font-weight: bold;">this</span>.myGetNextLineNum();
custInvoiceTable = next createInvoice();
<span style="color: #008800; font-weight: bold;">if</span>(origTransList.elements())
{
TaxUncommitted::deleteForDocumentHeader(tableNum(CustInvoiceTable), custInvoiceTable.RecId);
}
<span style="color: #008800; font-weight: bold;">return</span> custInvoiceTable;
}
<span style="color: #008800; font-weight: bold;">public</span> LineNum <span style="color: #0066bb; font-weight: bold;">myGetNextLineNum</span>()
{
CustInvoiceLine custInvoiceLine;
</pre><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;"> select</span> <span style="color: #0066bb; font-weight: bold;">maxof</span>(lineNum) <span style="color: #008800; font-weight: bold;">from</span> custInvoiceLine
<span style="color: #008800; font-weight: bold;">where</span> custInvoiceLine.ParentRecId == custInvoiceTable.RecId;
<span style="color: #008800; font-weight: bold;">return</span> custInvoiceLine.LineNum + <span style="color: #6600ee; font-weight: bold;">1</span>;
}
}
</pre></div>
</div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-14119052593014607922024-01-05T18:30:00.007-05:002024-01-05T19:05:57.342-05:00Check your data via SQL<p> Sometimes we need to check or validate some data in a dev box. The fastest way to do that is to run a query directly in MS SQL management studio.</p><p>For example, I have hundreds legal entities and want to know in which of them I have some Purchase orders. Voila:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjbA3YVJID1XfJrdMS4PmE_arKuJD-IijG4XmcVhRw9ux8ZdS5E30B2FB-Yqazg01JFTKserZx7nLqXVDv06zuAteScJb6ZZup_HwbAPsDIDg-ksJ83VPvaW34YIIEQNWXKMIGiSGAnuKh0jyZOu8EgZoviVibwzmfPpr-ocHxCjHhrkE85VMU1uZo3Sqc" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="245" data-original-width="427" src="https://blogger.googleusercontent.com/img/a/AVvXsEjbA3YVJID1XfJrdMS4PmE_arKuJD-IijG4XmcVhRw9ux8ZdS5E30B2FB-Yqazg01JFTKserZx7nLqXVDv06zuAteScJb6ZZup_HwbAPsDIDg-ksJ83VPvaW34YIIEQNWXKMIGiSGAnuKh0jyZOu8EgZoviVibwzmfPpr-ocHxCjHhrkE85VMU1uZo3Sqc=s16000" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><br /><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">select</span>
dataareaid <span style="color: #008800; font-weight: bold;">as</span> Company, <span style="color: #008800; font-weight: bold;">count</span>(RECID) <span style="color: #008800; font-weight: bold;">as</span> <span style="background-color: #fff0f0;">'Number of PO'</span>
<span style="color: #008800; font-weight: bold;">from</span> PURCHTABLE
<span style="color: #008800; font-weight: bold;">group</span> <span style="color: #008800; font-weight: bold;">by</span> DATAAREAID
<span style="color: #008800; font-weight: bold;">having</span> <span style="color: #008800; font-weight: bold;">count</span>(RECID) <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">1</span>
</pre></div>
<p></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-29660546696817170992023-09-19T12:49:00.003-04:002024-02-21T13:13:58.697-05:00How to create a new custom financial dimension value with description and other parameters via X++<p>User can add values manually to Custom dimension attribute type only. For all other backing entities it should go via standard table creation, say, new <i>CustTable </i>record, etc.</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhr59imdEi2aLEKJwdVGCsNuI7jiEy-sxlbA8GTqZCErQQl3LiX_MekQa2_wRQqZq2IiU8OLxlAK4ItheYF07_GACrfDnz2SMfP7jOkEMT2ozLLscbUTCd2N0yFneCkrV2uHhuxIzKZlraa01fjUsrAMFnOprnkD2ATe_9KmaAAecVhAeoE1B3f0FcZ8vA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="559" data-original-width="1121" src="https://blogger.googleusercontent.com/img/a/AVvXsEhr59imdEi2aLEKJwdVGCsNuI7jiEy-sxlbA8GTqZCErQQl3LiX_MekQa2_wRQqZq2IiU8OLxlAK4ItheYF07_GACrfDnz2SMfP7jOkEMT2ozLLscbUTCd2N0yFneCkrV2uHhuxIzKZlraa01fjUsrAMFnOprnkD2ATe_9KmaAAecVhAeoE1B3f0FcZ8vA=s16000" /></a></div><br />The easiest way to create a new <i>Custom list</i> dimension value is to use the standard service <b>DimensionValueService </b>as follows. Say, you need to create a new value by using <i>_newProjCategory </i>record fields.<p></p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">DimensionValueService dimensionValueService = <span style="color: #008800; font-weight: bold;">new</span> DimensionValueService();
DimensionValueContract dimensionValueContract = <span style="color: #008800; font-weight: bold;">new</span> DimensionValueContract();
dimensionValueContract.parmValue(_newProjCategory.Id);
dimensionValueContract.parmDimensionAttribute(myDimHelper::getProjCategoryAttribute);
dimensionValueContract.parmDescription(_newProjCategory.Name);
dimensionValueService.createDimensionValue(dimensionValueContract);
</pre></div>
<br /><p></p><p>It creates the display value as its description.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXACWs939uAiVI9ADVadzT4vMQAIzhoNqMupKafxQawmnhPjbq2h5GbE1r2zV5_UFI1ynjzNjRHMBp1QEg1L_l_2Bu5UaDgzUZD10xpPeLb3RLna8GwDNd_1oSE3M0yAlZ06U6dBrBjPZXUSt1GtEzsJK4elCDTYpFTczr_xetvo8KSksvOJNY540mcBI/s1729/2024-02-21_13-12-14.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="788" data-original-width="1729" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXACWs939uAiVI9ADVadzT4vMQAIzhoNqMupKafxQawmnhPjbq2h5GbE1r2zV5_UFI1ynjzNjRHMBp1QEg1L_l_2Bu5UaDgzUZD10xpPeLb3RLna8GwDNd_1oSE3M0yAlZ06U6dBrBjPZXUSt1GtEzsJK4elCDTYpFTczr_xetvo8KSksvOJNY540mcBI/s16000/2024-02-21_13-12-14.jpg" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><br /><p></p><p> </p><div id="gtx-anchor" style="height: 15.3846px; left: 355.849px; position: absolute; top: 801.095px; visibility: hidden; width: 15.3029px;"></div><div aria-describedby="bubble-2" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: 29px; opacity: 1; top: 826px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-2"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowup" style="left: 355.35px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-72962820750417437712023-09-02T18:53:00.002-04:002024-02-21T13:15:54.239-05:00Ledger dimension vs Default dimension<p> In short Ledger dimension it is Main account + default dimension.</p><p></p><p>So, if you need to replace any attribute value in a given Ledger dimension, do not forget to get a Default dimension first.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">LedgerDimensionFacade::getDefaultDimensionFromLedgerDimension(ledgerjournalTrans.LedgerDimension);
</pre></div><p></p><p>Then you can use this old good way.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">DimensionDefault newDim = DimensionHelper::setValueToDefaultDimension(hcmEmployment.DefaultDimension, DimensionAttribute::findByName(_dimensionName).RecId, _dimensionValue);
</pre></div><p>BTW, the opposite thing works like that:</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">LedgerDimensionFacade::serviceCreateLedgerDimension(ledgerDimensionMainAccount, inventTrans.defaultDimension);</pre></div>
Supporting method<br /><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> DimensionDefault <span style="color: #0066bb; font-weight: bold;">setValueToDefaultDimension</span>(DimensionDefault _dimensionDefault, RefRecId _dimensionAttributeRecId, DimensionValue _newDimensionValue)
{
DimensionAttributeValueSetStorage dimStorage;
DimensionDefault newDimensionDefault = _dimensionDefault;
DimensionAttributeValue dimensionAttributeValue;
<span style="color: #008800; font-weight: bold;">if</span> (_dimensionAttributeRecId)
{
dimStorage = DimensionAttributeValueSetStorage::find(_dimensionDefault);
<span style="color: #008800; font-weight: bold;">if</span> (_newDimensionValue)
{
dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(DimensionAttribute::find(_dimensionAttributeRecId), _newDimensionValue, <span style="color: #008800; font-weight: bold;">false</span>, <span style="color: #008800; font-weight: bold;">true</span>);
dimStorage.addItem(dimensionAttributeValue);
}
<span style="color: #008800; font-weight: bold;">else</span>
{
dimStorage.removeDimensionAttribute(_dimensionAttributeRecId);
}
newDimensionDefault = dimStorage.save();
}
<span style="color: #008800; font-weight: bold;">return</span> newDimensionDefault;
}
</pre></div>
<br />
Bigger usage example<p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;"> // replace TransactionType to the one from parameters</span>
<span style="color: #888888;">// first we need to get main account and default dimension from the originl transaction ledger dimension </span>
mainAccountRecId = LedgerDimensionFacade::getMainAccountRecIdFromLedgerDimension(_ledgerJournalTransOrig.LedgerDimension);
dimensionDefault = LedgerDimensionFacade::getDefaultDimensionFromLedgerDimension(_ledgerJournalTransOrig.LedgerDimension);
<span style="color: #888888;">// then replace this attribute with a new value</span>
dimensionDefault = myDimValueHelper::setDefaultDimensionValue(dimensionDefault, myDimensionConstants::TransactionType, LedgerParameters::find().myGLDimInvTransSale);
<span style="color: #888888;">// get default dimension for main account</span>
ledgerDimensionMainAccount = LedgerDefaultAccountHelper::getDefaultAccountFromMainAccountRecId(mainAccountRecId);
<span style="color: #888888;">// finally combine it with original main account to get a new ledger dimension</span>
ledgerJournalTrans.OffsetLedgerDimension = LedgerDimensionFacade::serviceCreateLedgerDimension(ledgerDimensionMainAccount, dimensionDefault);
ledgerJournalTrans.modifiedField(fieldNum(LedgerJournalTrans, OffsetLedgerDimension));
</pre></div>
<p></p>
<p> <a href="https://alexvoy.blogspot.com/2015/10/how-to-lookup-and-set-new-value-for.html">https://alexvoy.blogspot.com/2015/10/how-to-lookup-and-set-new-value-for.html</a></p><p>Thanks <a href="https://sashanazarov.blogspot.com/2018/11/generate-ledgerdimension-from-main.html">Sasha Nazarov</a> and <a href="https://community.dynamics.com/365/financeandoperations/b/ievgensaxblog/posts/d365foe-how-to-override-form-data-source-field-lookup-method">Ievgen Miroshnikov</a> and <a href="https://denistrunin.com/xpptools-devfindim/">Denis Trunin</a></p><div aria-describedby="bubble-8" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: 56px; opacity: 1; top: 663px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-8"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowdown" style="left: 381.575px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-89896665270373155472023-08-04T17:36:00.006-04:002024-02-21T13:19:14.770-05:00How to select\unselect all records in a form grid<p> While adding standard command button you can opt for SelectAll to mark all records in a form grid. However, there is no such a command for the opposite - unselect all records.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUrc4B6q5LNiz6HbyJUBNzyhqdxIThggSQQedgI0N96sH3oQGnLmwFS1izKrp9vuwWUrWjNYRXtrivzLBDDZ4M5OxweL3-o8DKNo27v6C8d3KS6WD2ViL3L_JTp8hEFmvR2piEfvovTno-udryhEONJT_Kca8S_Q_wFqiQd0EUV2HKBxPyh2xAZkc0rvQ/s604/commandButton.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="338" data-original-width="604" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUrc4B6q5LNiz6HbyJUBNzyhqdxIThggSQQedgI0N96sH3oQGnLmwFS1izKrp9vuwWUrWjNYRXtrivzLBDDZ4M5OxweL3-o8DKNo27v6C8d3KS6WD2ViL3L_JTp8hEFmvR2piEfvovTno-udryhEONJT_Kca8S_Q_wFqiQd0EUV2HKBxPyh2xAZkc0rvQ/w640-h358/commandButton.jpg" width="640" /></a></div><br /><p>You can easily achieve it by using the following method and two usual button form controls.</p><p>
<!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">[Form]
public <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">myForm</span> extends FormRun
{
public void selectAll(boolean _select)
{
VendPaymFormat_DS<span style="color: #333333;">.</span>markAllLoadedRecords(_select);
}
[Control(<span style="background-color: #fff0f0;">"Button"</span>)]
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">FormButtonControlSelectAll</span>
{
public void clicked()
{
element<span style="color: #333333;">.</span>selectAll(true);
<span style="color: #007020;">super</span>();
}
}
[Control(<span style="background-color: #fff0f0;">"Button"</span>)]
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">FormButtonControlUnSelectAll</span>
{
public void clicked()
{
element<span style="color: #333333;">.</span>selectAll(false);
<span style="color: #007020;">super</span>();
}
}
}
</pre></div>
<br /><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFIWcRLuK_p7MO_MDMMZfHIwQ4K88Y-ueNvXGaaOEBAyiHixmmMyV3QTIFhQxpm8OSOaNpSnmLXoXRfwy2-jQL2cyPbjaikk7FLkoc05U8J79IaUGaPHEHoroOMVDWMGy1A3OrNPhKyk6Ne1ajEdSPN09eFw9p-vfMEbByUFUBicdW2bF3d44BZVnGjKQ/s549/formdesign.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="267" data-original-width="549" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFIWcRLuK_p7MO_MDMMZfHIwQ4K88Y-ueNvXGaaOEBAyiHixmmMyV3QTIFhQxpm8OSOaNpSnmLXoXRfwy2-jQL2cyPbjaikk7FLkoc05U8J79IaUGaPHEHoroOMVDWMGy1A3OrNPhKyk6Ne1ajEdSPN09eFw9p-vfMEbByUFUBicdW2bF3d44BZVnGjKQ/w640-h312/formdesign.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLI3Y1hUlyjWRkrKOxqQtxm22YEOvfcdKWsKJ_YAZ3hJeKDkjzjSLQCQf_qtvmt9cuO52Ekhhal3jb9V1Qa1kXn49Kt7LhLoEnn2VVHujvum3-NsuRodBU_aQnms0DuYOtHGEANudCD1fmLMh157vRmFwSPRp1pP_x0WWg_scz0erLks0VBBufSvuJVt8/s562/2024-02-21_10-40-29.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="562" data-original-width="523" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLI3Y1hUlyjWRkrKOxqQtxm22YEOvfcdKWsKJ_YAZ3hJeKDkjzjSLQCQf_qtvmt9cuO52Ekhhal3jb9V1Qa1kXn49Kt7LhLoEnn2VVHujvum3-NsuRodBU_aQnms0DuYOtHGEANudCD1fmLMh157vRmFwSPRp1pP_x0WWg_scz0erLks0VBBufSvuJVt8/w298-h320/2024-02-21_10-40-29.jpg" width="298" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><p><br /></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-84050926896456711642023-08-04T16:13:00.006-04:002024-02-21T13:01:44.230-05:00How to get rid of a stuck report design in SSRS<p>It is difficult to say if your recent changes to an SSRS report design are really deployed. I suggest that any textbox be colored to visualize it (you can revert it in the end).</p><p>However, sometimes previous design is stuck on the server, and you still see no changes deployed, nevertheless, you already restarted Reporting services. Fortunately, there is a direct way to delete such a stubborn report from the server.</p><p>Open Report Server configuration manager as administrator and apply Portal URL setting if it is not done yet.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvFl7YCGKE0bDTUgel7nKZd8x-Ak9gZnxUjZCiuQpUhQsnZ4m0VjuW2ilGI-aNAWqbwi33asEhPcHtBTeAltm7VarAb0aPaPiY2uQyofPg0wdhhtOsYKXl0aWvQoSogXEus36jx0ceZUqp5YL_0djodSX6aV3X6374PE-dFivQ3w0ZgAXDtjZjAeIXRL8/s1799/2024-02-21_12-59-00.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="883" data-original-width="1799" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvFl7YCGKE0bDTUgel7nKZd8x-Ak9gZnxUjZCiuQpUhQsnZ4m0VjuW2ilGI-aNAWqbwi33asEhPcHtBTeAltm7VarAb0aPaPiY2uQyofPg0wdhhtOsYKXl0aWvQoSogXEus36jx0ceZUqp5YL_0djodSX6aV3X6374PE-dFivQ3w0ZgAXDtjZjAeIXRL8/w640-h314/2024-02-21_12-59-00.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p>Then go for your report and delete it.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZwVtlgG8pRwW-gpJTiSFV1Ya-BdlJuHz8Q8RY3flvyi77T1cG-w3etOJKDd_GrC-psEI3zuKw-Kxx_oak9ta5Ype1qcJV7ZeRpWVMHVEG2j4NTKd5ZJ-ug8LmEoWLRsGsXI0UFUaXMCFGZ2Xojtwq0lCveMquVcK4byGyT1YFmrTsdMzTxukxLJa3yNE/s1192/2024-02-21_12-56-38.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="838" data-original-width="1192" height="450" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZwVtlgG8pRwW-gpJTiSFV1Ya-BdlJuHz8Q8RY3flvyi77T1cG-w3etOJKDd_GrC-psEI3zuKw-Kxx_oak9ta5Ype1qcJV7ZeRpWVMHVEG2j4NTKd5ZJ-ug8LmEoWLRsGsXI0UFUaXMCFGZ2Xojtwq0lCveMquVcK4byGyT1YFmrTsdMzTxukxLJa3yNE/w640-h450/2024-02-21_12-56-38.jpg" width="640" /></a></div><p>Next deployment should be OK.</p><br />wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-52408269171851600812023-07-28T18:19:00.004-04:002024-02-21T12:47:41.486-05:00XDS in action: How to restraint access to data based on the current user employee<p><a href="https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/sysadmin/extensible-data-security-policies">Extensible Data Security (XDS) policies</a> allow restraint access to D365FO data in a very flexible way.</p><p>Business case: a user can see those purchase orders and their related confirmations only if he or she is Requester. The whole project can basically contain three objects: role, query, and policy.</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><br /></div></div><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgys0N7U0EHwkk3WA2WuMTIp6-lRvdNbBMo8VNM-jV9SpxBDcBw3hsjDs4A9yhcUbvI3mHJaOd0ms_VibjHmVFrWW9I4U8mzlcaRlN8U6zz0qXMeViJ3mMOb0mQ5jRaBq1O2g_G7vzO0NWsDLh7AMUsy-CCSiaojIfOhJvoUr4FuD0CRafcvYtYmjyqeGw/s807/2024-02-21_12-28-39.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="445" data-original-width="807" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgys0N7U0EHwkk3WA2WuMTIp6-lRvdNbBMo8VNM-jV9SpxBDcBw3hsjDs4A9yhcUbvI3mHJaOd0ms_VibjHmVFrWW9I4U8mzlcaRlN8U6zz0qXMeViJ3mMOb0mQ5jRaBq1O2g_G7vzO0NWsDLh7AMUsy-CCSiaojIfOhJvoUr4FuD0CRafcvYtYmjyqeGw/w320-h176/2024-02-21_12-28-39.jpg" width="320" /></a></div></div></blockquote><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><br /></div></div><p>After creating a specific security role, we need to create a query with <i>HCMWorker </i>table so that it is filtered for the current user.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIjSEEhLlZc528YTnBXKmWi8IPpeq5gfbxsDJ0rUJst7NUHFaQrnTH-ebUpjtCDFSlEZgC7FVMI5tm8TIUFAi34PlM2qxHB0YcOg7sT4E7Z4rd9KPzRxevdQdj-rKnXEpzWVR900GuwKyuIRe3f-pT0NQ9C-VvrsNHtW92ACFld88OQ20DyhiZpTtgIeo/s936/2024-02-21_12-32-38.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="358" data-original-width="936" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIjSEEhLlZc528YTnBXKmWi8IPpeq5gfbxsDJ0rUJst7NUHFaQrnTH-ebUpjtCDFSlEZgC7FVMI5tm8TIUFAi34PlM2qxHB0YcOg7sT4E7Z4rd9KPzRxevdQdj-rKnXEpzWVR900GuwKyuIRe3f-pT0NQ9C-VvrsNHtW92ACFld88OQ20DyhiZpTtgIeo/w640-h245/2024-02-21_12-32-38.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0xKg4VWrrgqjVrjtAUCt3NDACmzq4l_M3TF32iUy7FXBHLJKOtfqqNROI0lJh02-e8zVoiaXTWFSLd0RkuNTm9kRlprRi_zR7jlnKdV_6qL981msd0qb0vGhfIx1wcDvh4w3YvrBI6p3yAWARtJ0a3JDzPOSBwhA7Rx2UFpqGm4-oZO3trPxxLUiD3EI/s752/2024-02-21_12-36-18.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="473" data-original-width="752" height="402" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0xKg4VWrrgqjVrjtAUCt3NDACmzq4l_M3TF32iUy7FXBHLJKOtfqqNROI0lJh02-e8zVoiaXTWFSLd0RkuNTm9kRlprRi_zR7jlnKdV_6qL981msd0qb0vGhfIx1wcDvh4w3YvrBI6p3yAWARtJ0a3JDzPOSBwhA7Rx2UFpqGm4-oZO3trPxxLUiD3EI/w640-h402/2024-02-21_12-36-18.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p>All constrained tables should be added to the policy by referencing a particular relation (<i>PurchTable</i>, for example, has two relations with <i>HCMWorker </i>table; thus, we need to pick up the required one related to Requester field)</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX9HUHtbVkwQ9C-RLlihlROkx1usW9NyGwISdpMNq-ulS5nfStlPAoFAqK_ZIKvdwsruB92TLVdE1rNONkMUMB0_YTZafSmj09UXT1tXdvrU1QIsy3TQAy2mQSFvAT2Pqb1LBTIgpAi22qXj_4i3XEHiIjfEN9OtOdB76MD0dnIetcoaG6vJG13RN8rn4/s753/2024-02-21_12-37-36.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="331" data-original-width="753" height="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX9HUHtbVkwQ9C-RLlihlROkx1usW9NyGwISdpMNq-ulS5nfStlPAoFAqK_ZIKvdwsruB92TLVdE1rNONkMUMB0_YTZafSmj09UXT1tXdvrU1QIsy3TQAy2mQSFvAT2Pqb1LBTIgpAi22qXj_4i3XEHiIjfEN9OtOdB76MD0dnIetcoaG6vJG13RN8rn4/w640-h282/2024-02-21_12-37-36.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhstgYXvnqGDbwrpcZufK4PhRo3e7H7MQqh7GrykRLvVmjKGbI3wfopsefZpHGSBlZ7_imV2vMt3VOlm1viNgAq_-KCwTjGiN3OIR6LILRNHeR8_Sl9qAek6Vjx1PwWIGEvJzDvLs85daoSteoxNqormLBjSlcUsofnzO6Vph8G9_6npPXPVvVxSf5Clcg/s758/2024-02-21_12-39-42.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="470" data-original-width="758" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhstgYXvnqGDbwrpcZufK4PhRo3e7H7MQqh7GrykRLvVmjKGbI3wfopsefZpHGSBlZ7_imV2vMt3VOlm1viNgAq_-KCwTjGiN3OIR6LILRNHeR8_Sl9qAek6Vjx1PwWIGEvJzDvLs85daoSteoxNqormLBjSlcUsofnzO6Vph8G9_6npPXPVvVxSf5Clcg/w640-h396/2024-02-21_12-39-42.jpg" width="640" /></a></div><br /></div><br /><p>Note: we can create a join expression if a required relation does not exist for a given table.</p><p>Once the project built and synchronized, we can assign this new role along with some standard ones to a user. For example sake, I added Ada to my user.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4CvwScfyvQsM9chZUM-Hw2QxMVw12purdU5Mo8B5hpNQ00-n1VdZDj6PH4qtwHAx3DleYyGkOohNiI9_ZsWZYOGfohPU_JFFvNas8k_qExnbSzRYaq2cqRu9KT8kRiQm3M8i52DezzNtxxK6Szwmr2a3_UzvQKrmz0D0hTtVr0bz8I4ivPEURAzSI1pQ/s669/2024-02-21_12-43-51.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="611" data-original-width="669" height="584" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4CvwScfyvQsM9chZUM-Hw2QxMVw12purdU5Mo8B5hpNQ00-n1VdZDj6PH4qtwHAx3DleYyGkOohNiI9_ZsWZYOGfohPU_JFFvNas8k_qExnbSzRYaq2cqRu9KT8kRiQm3M8i52DezzNtxxK6Szwmr2a3_UzvQKrmz0D0hTtVr0bz8I4ivPEURAzSI1pQ/w640-h584/2024-02-21_12-43-51.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1DkVBzsOukwmJWUx0OOsapPUEac1c_6iyRQMMZX9i5PSrsV5iAHYg4p4hc9BRuuxlr4ETNlMfuUiZ72Z8rfNLikCrMzv73lzzU4TQB5TdPgZutkeHRBnpiOnc3fccLjFejYt0S1uE2cdtNZ5nCPFylkm62wvfeeKI3xtC-hAHAxybv8ftNPIfIxAC7mU/s935/2024-02-21_12-46-34.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="935" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1DkVBzsOukwmJWUx0OOsapPUEac1c_6iyRQMMZX9i5PSrsV5iAHYg4p4hc9BRuuxlr4ETNlMfuUiZ72Z8rfNLikCrMzv73lzzU4TQB5TdPgZutkeHRBnpiOnc3fccLjFejYt0S1uE2cdtNZ5nCPFylkm62wvfeeKI3xtC-hAHAxybv8ftNPIfIxAC7mU/w640-h220/2024-02-21_12-46-34.jpg" width="640" /></a></div><br />wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-7424705028438532062023-06-12T19:38:00.001-04:002023-06-12T19:38:15.577-04:00Complete pack/unpack pack for RunBaseBatch adventure<p><b><span style="font-size: medium;">Usage</span></b></p><p>We can use pack-unpack methods in <i>RunBaseBatch </i>classes and all its descendants to save and/or store the state of an object, and then later re-instantiate the same object.</p><p>We need it, for example, to use the user's input for any batch job: some parameters can be used when a batch job is executed on the server. </p><p><b><span style="font-size: medium;">Documentation</span></b></p><p>Microsoft doc article is <a href="https://learn.microsoft.com/en-us/dynamicsax-2012/developer/pack-unpack-design-pattern">here</a>.</p><p>Quote: "A reinstantiated object is not the same object as the one that was saved. It is just an object of the same class whose members contain the same information." </p><p>You need to teleport your objects without <a href="https://www.imdb.com/title/tt0091064/">a fly</a> or other bugs.</p><p><b><span style="font-size: medium;">Case examples</span></b></p><p><b>Basics</b></p><p>Basic example of such a class is <i>Tutorial_RunbaseBatch</i>.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> TransDate transDate;
CustAccount custAccount;
<span style="color: #557799;">#define.CurrentVersion(1)</span>
<span style="background-color: #ffaaaa; color: red;">#</span>localmacro.CurrentList
transDate,
custAccount
<span style="background-color: #ffaaaa; color: red;">#</span>endmacro
<span style="color: #008800; font-weight: bold;">public</span> container <span style="color: #0066bb; font-weight: bold;">pack</span>()
{
<span style="color: #008800; font-weight: bold;">return</span> [<span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion,<span style="background-color: #ffaaaa; color: red;">#</span>CurrentList];
}
<span style="color: #008800; font-weight: bold;">public</span> boolean <span style="color: #0066bb; font-weight: bold;">unpack</span>(container packedClass)
{
Version version = RunBase::getVersion(packedClass);
;
<span style="color: #008800; font-weight: bold;">switch</span> (version)
{
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion:
<span style="color: #0000cc;"> [version,#CurrentList]</span> = packedClass;
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">default</span>:
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">false</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">true</span>;
}
</pre></div>
<p></p><p><b>Containers</b></p><p>Basically you can add a container directly to pack() or convert a container to a string and save the latter. Opposite conversion required for restoring. </p><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;">container siteIds;
str siteIdsStr;
<span style="color: #557799;">#define.CurrentVersion(1)</span>
<span style="color: #557799;">#define.Version1(1)</span>
<span style="background-color: #ffaaaa; color: red;">#</span>localmacro.CurrentList
siteIdsStr
<span style="background-color: #ffaaaa; color: red;">#</span>endmacro
<span style="color: #008800; font-weight: bold;">public</span> boolean <span style="color: #0066bb; font-weight: bold;">getFromDialog</span>()
{
...
<span> </span><span style="color: #888888;">// convert it to string for pack/unpack</span>
siteIdsStr = con2Str(siteIds);
<span> </span><span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0066bb; font-weight: bold;">super</span>();
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">dialogPostRun</span>(DialogRunbase _dialog)
{
FormRun formRun;
super(dialog);
formRun = _dialog.dialogForm().formRun();
<span style="color: #008800; font-weight: bold;">if</span> (formRun)
{
<span style="color: #888888;">// if we restored from last values</span>
<span style="color: #008800; font-weight: bold;">if</span>(siteIdsStr)
{
<span style="color: #888888;">//then we convert the string to container</span>
siteIds = str2con(siteIdsStr);
}
}
}
</pre></div>
<p>See the following article for the complete usage <a href="https://alexvoy.blogspot.com/2014/11/dialog-field-with-multiple-choice.html">https://alexvoy.blogspot.com/2014/11/dialog-field-with-multiple-choice.html</a></p><p><b>Tables</b></p><p>Save an unique key value, say, <i>RecId </i>to find a target buffer after <i>unpack</i>()</p><p><b>Collection types</b></p><p>Maps, lists, and sets are equipped with method pack, which you can use directly for packing.</p><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;"> // collections</span>
List list;
Map map;
Set <span style="color: #008800; font-weight: bold;">set</span>;
<span style="color: #888888;">// saved states</span>
container packedCont;
packedCont = list.pack();
list = List::create(packedCont);
packedCont = map.pack();
map = Map::create(packedCont);
packedCont = <span style="color: #008800; font-weight: bold;">set</span>.pack();
<span style="color: #008800; font-weight: bold;">set</span> = Set::create(packedCont);</pre></div><p><b>Queries</b></p><p>How to pack/unpack a query among other parameters, you can find in <i>IntrastatTransfer </i>class.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> QueryRun queryRunIntrastatTransfer;
container <span style="color: #0066bb; font-weight: bold;">pack</span>()
{
<span style="color: #008800; font-weight: bold;">return</span> [<span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion,<span style="background-color: #ffaaaa; color: red;">#</span>CurrentList,queryRunIntrastatTransfer.pack()];
}
boolean <span style="color: #0066bb; font-weight: bold;">unpack</span>(container packedClass)
{
Integer version = conPeek(packedClass,<span style="color: #6600ee; font-weight: bold;">1</span>);
container packedQuery;
<span style="color: #008800; font-weight: bold;">switch</span> (version)
{
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion:
<span style="color: #0000cc;"> [version,#CurrentList,packedQuery]</span> = packedClass;
<span style="color: #008800; font-weight: bold;">if</span> (packedQuery)
{
queryRunIntrastatTransfer = <span style="color: #008800; font-weight: bold;">new</span> QueryRun(packedQuery);
}
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">default</span>:
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">false</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">true</span>;
}
</pre></div>
<p></p><p><b>Subclasses</b></p><p>How to pack/unpack additional parameters in a subclass.</p><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">myVendCreateGlobalPaymJournal</span> extends CustVendCreatePaymJournal_Vend
NoYes myParm;
<span style="color: #557799;">#define.CurrentVersion(1)</span>
<span style="background-color: #ffaaaa; color: red;">#</span>localmacro.CurrentList
myParm
<span style="background-color: #ffaaaa; color: red;">#</span>endmacro
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Pack the new parameters</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns>standard list of parameters with the new ones</returns></span>
<span style="color: #008800; font-weight: bold;">public</span> container <span style="color: #0066bb; font-weight: bold;">pack</span>()
{
<span style="color: #008800; font-weight: bold;">return</span> [<span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion,<span style="background-color: #ffaaaa; color: red;">#</span>CurrentList] + [super()];
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Unpacks saved parameters</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_packedClass">Parameters container</param></span>
<span style="color: #888888;">/// <returns>True if OK</returns></span>
<span style="color: #008800; font-weight: bold;">public</span> boolean <span style="color: #0066bb; font-weight: bold;">unpack</span>(container _packedClass)
{
Integer version = conPeek(_packedClass,<span style="color: #6600ee; font-weight: bold;">1</span>);
container packedBase;
<span style="color: #008800; font-weight: bold;">switch</span> (version)
{
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion:
<span style="color: #0000cc;"> [version, #CurrentList, packedBase]</span> = _packedClass;
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0066bb; font-weight: bold;">super</span>(packedBase);
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0066bb; font-weight: bold;">super</span>(_packedClass);
}</pre></div><p><b>Extensions</b></p><p>How to pack/unpack additional parameters in an augmented class (extension).</p><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// We are going to use a new additional parameter</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #0000cc;">[ExtensionOf(classStr(<ClassName>))]</span>
<span style="color: #008800; font-weight: bold;">public</span> final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">My</span><ClassName>_Extension
{
<span style="color: #008800; font-weight: bold;">private</span> boolean myNewParm;
<span style="color: #557799;">#define.CurrentVersion(1)</span>
<span style="background-color: #ffaaaa; color: red;">#</span>localmacro.CurrentList
myNewParm
<span style="background-color: #ffaaaa; color: red;">#</span>endmacro
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// myNewParm access</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_parm">boolean</param></span>
<span style="color: #888888;">/// <returns>boolean</returns></span>
<span style="color: #008800; font-weight: bold;">public</span> boolean <span style="color: #0066bb; font-weight: bold;">parmMyNewParm</span>(boolean _parm = myNewParm)
{
myNewParm= _parm;
<span style="color: #008800; font-weight: bold;">return</span> myNewParm;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Extends Pack</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns>container</returns></span>
<span style="color: #008800; font-weight: bold;">public</span> container <span style="color: #0066bb; font-weight: bold;">pack</span>()
{
container packedClass = next pack();
<span style="color: #008800; font-weight: bold;">return</span> SysPackExtensions::appendExtension(packedClass, classStr(My<ClassName>_Extension), <span style="color: #008800; font-weight: bold;">this</span>.myPack());
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Extends Unpack</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "packedClass">container</param></span>
<span style="color: #888888;">/// <returns>boolean</returns></span>
<span style="color: #008800; font-weight: bold;">private</span> boolean <span style="color: #0066bb; font-weight: bold;">myUnpack</span>(container packedClass)
{
Integer version = RunBase::getVersion(packedClass);
<span style="color: #008800; font-weight: bold;">switch</span> (version)
{
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion:
<span style="color: #0000cc;"> [version, #currentList]</span> = packedClass;
<span style="color: #008800; font-weight: bold;">break</span>;
<span style="color: #008800; font-weight: bold;">default</span>:
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">false</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">true</span>;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Packs my locals</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns>container</returns></span>
<span style="color: #008800; font-weight: bold;">private</span> container <span style="color: #0066bb; font-weight: bold;">myPack</span>()
{
<span style="color: #008800; font-weight: bold;">return</span> [<span style="background-color: #ffaaaa; color: red;">#</span>CurrentVersion, <span style="background-color: #ffaaaa; color: red;">#</span>CurrentList];
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Extends unpack</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_packedClass">container</param></span>
<span style="color: #888888;">/// <returns>boolean</returns></span>
<span style="color: #008800; font-weight: bold;">public</span> boolean <span style="color: #0066bb; font-weight: bold;">unpack</span>(container _packedClass)
{
boolean result = next unpack(_packedClass);
<span style="color: #008800; font-weight: bold;">if</span> (result)
{
container myState = SysPackExtensions::findExtension(_packedClass, classStr(My<ClassName>_Extension));
<span style="color: #888888;">//Also unpack the extension</span>
<span style="color: #008800; font-weight: bold;">if</span> (!<span style="color: #008800; font-weight: bold;">this</span>.myUnpack(myState))
{
result = <span style="color: #008800; font-weight: bold;">false</span>;
}
}
<span style="color: #008800; font-weight: bold;">return</span> result;
}
}
</pre></div>
<p>Originally from <a href="https://alexvoy.blogspot.com/2022/02/additional-parameters-in-runbasebatch.html">https://alexvoy.blogspot.com/2022/02/additional-parameters-in-runbasebatch.html</a></p><p>Please, ping me if I missed anything.</p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-90169404828080662602023-05-08T21:43:00.007-04:002023-05-08T21:43:52.055-04:00How to create a new folder on Sharepoint<p>T<span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Web", sans-serif; font-size: 14px;">here are some useful code behind <i>OfficeSharePointFolderSelectionDiaolog </i>form; however, there is a limitation.</span></p><p><span style="font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Web", sans-serif; font-size: 14px;"></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh5Gc61Z_FOO_J50qPON-LvqiyJs4kMiiWjWx3sk908ty3bABHnF6DjyLOeMBuuMkNuYRZmYj_KHB1TIIdnGXjPOdSZZ01cWs9tRaDXAqhXGDlKPV0iFKBOmdwH6lsRDnvBdp2fnZJP9DBXQcwYi-_OLa1cRIWYFd2z_um_OVmx609_BhYIo5K4Kuhy" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="703" data-original-width="1120" src="https://blogger.googleusercontent.com/img/a/AVvXsEh5Gc61Z_FOO_J50qPON-LvqiyJs4kMiiWjWx3sk908ty3bABHnF6DjyLOeMBuuMkNuYRZmYj_KHB1TIIdnGXjPOdSZZ01cWs9tRaDXAqhXGDlKPV0iFKBOmdwH6lsRDnvBdp2fnZJP9DBXQcwYi-_OLa1cRIWYFd2z_um_OVmx609_BhYIo5K4Kuhy=s16000" /></a></div><br />Well, we can create a new folder via REST API call as follows. Take note that the access token is created in <span style="color: #0066bb; font-weight: bold;">testSharePointConnection</span><p></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.Dynamics.Platform.Integration.SharePoint</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Net</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Net.Http</span>;
<span style="color: #0000cc;">[Form]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">wzhSPFolderForm</span> extends FormRun
{
str apiUrl;
System.Exception ex;
ISharePointProxy proxy;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">init</span>()
{
super();
fNewFolder.text(<span style="background-color: #ffaaaa; color: red;">'</span>_wzhNewFolder<span style="background-color: #ffaaaa; color: red;">'</span>);
fServer.text(<span style="background-color: #ffaaaa; color: red;">'</span>https:<span style="color: #888888;">//wzhServer.sharepoint.com');</span>
fRootFolder.text(<span style="background-color: #ffaaaa; color: red;">'</span>Shared Documents<span style="background-color: #ffaaaa; color: red;">'</span>);
}
<span style="color: #008800; font-weight: bold;">public</span> boolean <span style="color: #0066bb; font-weight: bold;">testSharePointConnection</span>()
{
str src = fServer.text();
boolean validConnection = <span style="color: #008800; font-weight: bold;">false</span>;
<span style="color: #008800; font-weight: bold;">if</span>(src)
{
System.UriBuilder builder = <span style="color: #008800; font-weight: bold;">new</span> System.UriBuilder(src);
str hostName = builder.Host;
str siteName = fRootFolder.text();
str externalId = xUserInfo::getExternalId();
proxy = SharePointHelper::CreateProxy(hostName, <span style="color: #0044dd;">'/'</span>, externalId);
<span style="color: #008800; font-weight: bold;">if</span>(proxy)
{
<span style="color: #008800; font-weight: bold;">if</span>(SharePointHelper::VerifyAuthentication(proxy))
{
validConnection = <span style="color: #008800; font-weight: bold;">true</span>;
info(strfmt(<span style="background-color: #ffaaaa; color: red;">'</span>@ApplicationFoundation:SPServerCommunicationSuccess<span style="background-color: #ffaaaa; color: red;">'</span>, hostName));
}
<span style="color: #008800; font-weight: bold;">else</span>
{
info(strfmt(<span style="background-color: #ffaaaa; color: red;">'</span>@ApplicationFoundation:SPServerUserNotAuthorized<span style="background-color: #ffaaaa; color: red;">'</span>, hostName));
}
}
<span style="color: #008800; font-weight: bold;">else</span>
{
info(strfmt(<span style="background-color: #ffaaaa; color: red;">'</span>@ApplicationFoundation:SPSelectionDlg_ErrorNoProxy<span style="background-color: #ffaaaa; color: red;">'</span>, hostName));
}
}
<span style="color: #008800; font-weight: bold;">return</span> validConnection;
}
<span style="color: #008800; font-weight: bold;">public</span> str <span style="color: #0066bb; font-weight: bold;">GetAuthorizationToken</span>()
{
<span style="color: #008800; font-weight: bold;">return</span> proxy.AccessToken;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">createSPFolder</span>()
{
apiUrl = strFmt(<span style="background-color: #fff0f0;">"%1/_api/web/lists/getbytitle('%2')/rootfolder/folders/add('%3')"</span>, fServer.text(), fRootFolder.text(), fNewFolder.text());
<span style="color: #008800; font-weight: bold;">try</span>
{
<span style="color: #008800; font-weight: bold;">if</span>(<span style="color: #008800; font-weight: bold;">this</span>.testSharePointConnection())
{
str token = <span style="color: #008800; font-weight: bold;">this</span>.GetAuthorizationToken();
System.Net.WebHeaderCollection httpHeader = <span style="color: #008800; font-weight: bold;">new</span> System.Net.WebHeaderCollection();
httpHeader.Add(<span style="background-color: #fff0f0;">"Authorization"</span>, <span style="background-color: #ffaaaa; color: red;">'</span>Bearer <span style="background-color: #ffaaaa; color: red;">'</span> + token);
HttpWebRequest request = System.Net.WebRequest::Create(apiUrl);
request.set_Headers(httpHeader);
request.set_ContentLength(<span style="color: #6600ee; font-weight: bold;">0</span>);
request.set_Method(<span style="background-color: #fff0f0;">"POST"</span>);
request.set_ContentType(<span style="background-color: #fff0f0;">"application/json;odata=verbose"</span>);
System.Net.HttpWebResponse response = request.GetResponse();
<span style="color: #333399; font-weight: bold;">int</span> statusCode = response.get_StatusCode();
info(strFmt(<span style="background-color: #fff0f0;">"HTTP status code: %1"</span>, statusCode));
}
}
<span style="color: #008800; font-weight: bold;">catch</span>
{
<span style="color: #888888;">//exception</span>
ex = CLRInterop::getLastException().GetBaseException();
error(ex.get_Message());
}
}
<span style="color: #0000cc;"> [Control("Button")]</span>
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">bCreateREST</span>
{
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">///</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">clicked</span>()
{
element.createSPFolder();
super();
}
}
<span style="color: #0000cc;"> [Control("Button")]</span>
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">bTestConnection</span>
{
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">///</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">clicked</span>()
{
element.testSharePointConnection();
super();
}
}
}
</pre></div>
<p></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-23322495056539256942023-04-20T13:06:00.003-04:002024-02-21T13:33:29.497-05:00X++ to run XIRR<p>I created a small X++ wrapper to call <a href="https://support.microsoft.com/en-us/office/xirr-function-de1242ec-6477-445b-b11b-a303ad9adc9d" target="_blank">XIRR function</a> from the C# project provided by <a href="https://github.com/klearlending/XIRR">https://github.com/klearlending/XIRR</a> (Thank you!) </p><p>You can test XIRR function in Excel, btw.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">tmxExcelFinance</span>;
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Implements various financial functions</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">myFinanceFunction</span>
{
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Calculates XIRR value</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_cashFlows">List of containers kind [cashflow amount, its date]</param></span>
<span style="color: #888888;">/// <param name = "_decimals">how many decimals to calculate</param></span>
<span style="color: #888888;">/// <param name = "_maxRate">Maximum rate</param></span>
<span style="color: #888888;">/// <returns>XIRR value</returns></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> real <span style="color: #0066bb; font-weight: bold;">calculateXIRR</span>(List _cashFlows, <span style="color: #333399; font-weight: bold;">int</span> _decimals, real _maxRate = <span style="color: #6600ee; font-weight: bold;">1000000</span>)
{
<span style="color: #333399; font-weight: bold;">var</span> cashFlows = <span style="color: #008800; font-weight: bold;">new</span> System.Collections.Generic.List<CashFlowDates>();
System.Collections.IEnumerable cashFlowsI;
ListEnumerator leC = _cashFlows.getEnumerator();
System.Double dbl;
System.DateTime dt;
<span style="color: #008800; font-weight: bold;">while</span>(leC.moveNext())
{
<span style="color: #0000cc;"> [dbl, dt]</span> = leC.current();
cashFlows.Add(<span style="color: #008800; font-weight: bold;">new</span> CashFlowDates(dbl, dt));
}
<span style="color: #888888;">// convert to iterable</span>
cashFlowsI = cashFlows;
<span style="color: #008800; font-weight: bold;">return</span> XIRR::Calc(cashFlowsI, _decimals, _maxRate);
}
}
</pre></div>
<p></p><p>This is how we can call the wrapper</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">calculateXIRRFromInvestmentDetailsLineTmp</span>(RefRecId _projTableRecId, myInvestmentDetailsLineTmp _myInvestmentDetailsLineTmp)
{
List listCashFlowsDates = <span style="color: #008800; font-weight: bold;">new</span> List(Types::Container);
myInvestmentDetailsLineTmp myInvestmentDetailsLineTmpLocal;
myInvestmentDetailsLineTmpLocal.linkPhysicalTableInstance(_myInvestmentDetailsLineTmp);
<span style="color: #008800; font-weight: bold;">while</span> <span style="color: #008800; font-weight: bold;">select</span> myInvestmentDetailsLineTmpLocal
{
listCashFlowsDates.addEnd([myInvestmentDetailsLineTmpLocal.TransactionCurrencyAmount, DateTimeUtil::newDateTime(myInvestmentDetailsLineTmpLocal.LineDate, <span style="color: #6600ee; font-weight: bold;">0</span>)]);
}
myProjXIRRTable.XIRRValue = myFinanceFunction::calculateXIRR(listCashFlowsDates, <span style="color: #6600ee; font-weight: bold;">4</span>);
...
</pre></div>
<p></p><p>Or</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> cashFlows1 = <span style="color: #008800; font-weight: bold;">new</span> List (Types::Container);
cashFlows1.addEnd([-<span style="color: #6600ee; font-weight: bold;">10000</span>,str2Date(<span style="background-color: #fff0f0;">"01/01/2008"</span>, <span style="color: #6600ee; font-weight: bold;">123</span>)]);
cashFlows1.addEnd([<span style="color: #6600ee; font-weight: bold;">2750</span>, str2Date(<span style="background-color: #fff0f0;">"01/03/2008"</span>, <span style="color: #6600ee; font-weight: bold;">123</span>)]);
cashFlows1.addEnd([<span style="color: #6600ee; font-weight: bold;">4250</span>, str2Date(<span style="background-color: #fff0f0;">"30/10/2008"</span>, <span style="color: #6600ee; font-weight: bold;">123</span>)]);
cashFlows1.addEnd([<span style="color: #6600ee; font-weight: bold;">3250</span>, str2Date(<span style="background-color: #fff0f0;">"15/02/2009"</span>, <span style="color: #6600ee; font-weight: bold;">123</span>)]);
cashFlows1.addEnd([<span style="color: #6600ee; font-weight: bold;">2750</span>, str2Date(<span style="background-color: #fff0f0;">"01/04/2009"</span>, <span style="color: #6600ee; font-weight: bold;">123</span>)]);
res = myFinanceFunction::calculateXIRR(cashFlows1, <span style="color: #6600ee; font-weight: bold;">10</span>);
</pre></div>
<p></p><p>Notes about the solution creation.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVqKb67VGqQ2ZO85I8ia6MkzHFzpwKHa1X9b7m87af-wAq7OUIYSPMFMiGzFExZ92UnpiRTg7NHqlifKFLngzMixa8cHZMbjwZ5FyDe6sim5pB_6fClRIDGMdqdO-qF2lTCXj_XJCR7Sj6PlKB5TuoUVE6KuWJIOvOrNurAr-G9pclL9YvX0sbQqHJFRs/s1917/2024-02-21_13-31-28.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="261" data-original-width="1917" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVqKb67VGqQ2ZO85I8ia6MkzHFzpwKHa1X9b7m87af-wAq7OUIYSPMFMiGzFExZ92UnpiRTg7NHqlifKFLngzMixa8cHZMbjwZ5FyDe6sim5pB_6fClRIDGMdqdO-qF2lTCXj_XJCR7Sj6PlKB5TuoUVE6KuWJIOvOrNurAr-G9pclL9YvX0sbQqHJFRs/s16000/2024-02-21_13-31-28.jpg" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p>D365FO project must be <TargetFrameworkVersion>v4.6</TargetFrameworkVersion></p><p><br /></p><p>Last remark. I tried to implemented the same algorithm in X++, but I bumped into two limitations.</p><p>First, there is a limit for recursion depth - 400 levels; we can flatten it, though. </p><p>Second, real loses required decimals and ends up with division by zero.</p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-7885160258873839252023-04-09T15:59:00.003-04:002024-02-21T13:44:53.706-05:00Two outer joined tables in a report without duplicates from both sides<p> I cannot find a particular term for this type of join; so I called it 'hanging left outer join'.</p><p><br /></p><p>Let's state the problem.</p><p><br /></p><p>We have two tables:</p><p>- LedgerJournalTrans (trans) with a field mgcProjId, which is a reference to ProjTable.</p><p>- myDetails (details), which may have 0..N records for certain records from ProjTable.</p><p><br /></p><p>Examples of data in both may look like the following:</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgJlNxlYwHotpiJtjZooTpFUghyshF1Z-HyrAoqP-EOQ-C9mB6ApMUXI5mqwOsL36rrcMCEtLHMW41hGhC-rJDeJen7bmelSED0V1_kSJBbWLHGuj5rjrxSMtIhi6eNoUsZnIhFRnRFEwypMj1IC8h6cV-KoQvcGhFYC3xVSuUpLSTncJVh11YsObKi" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="361" data-original-width="241" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEgJlNxlYwHotpiJtjZooTpFUghyshF1Z-HyrAoqP-EOQ-C9mB6ApMUXI5mqwOsL36rrcMCEtLHMW41hGhC-rJDeJen7bmelSED0V1_kSJBbWLHGuj5rjrxSMtIhi6eNoUsZnIhFRnRFEwypMj1IC8h6cV-KoQvcGhFYC3xVSuUpLSTncJVh11YsObKi=w213-h320" width="213" /></a></div><br />If we apply standard outer join, the output will be as follows<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjX6B9WcwUXOAHGp-EbJ7xsxZxCMa3JqNQ3JVbC9HMt2nrXWxB52XKMefObb6ILJuFKi2VUzTErujC5wwWjfG6Bd459TnZWqNdvpTAgq0F1UClYV7kirsZrOmR356QAX2U1LyIP1TkhM84MMOlMwm90ejmw_FqbmwBbhtwH_gsmbp0ieqxYcMF6QZda" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="265" data-original-width="241" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjX6B9WcwUXOAHGp-EbJ7xsxZxCMa3JqNQ3JVbC9HMt2nrXWxB52XKMefObb6ILJuFKi2VUzTErujC5wwWjfG6Bd459TnZWqNdvpTAgq0F1UClYV7kirsZrOmR356QAX2U1LyIP1TkhM84MMOlMwm90ejmw_FqbmwBbhtwH_gsmbp0ieqxYcMF6QZda" width="218" /></a></div><br />But we need to print all details records by 'hanging' them against the same projId, like this<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgbGZbd7t4JvY4ZwpGSAYjuLKqCuODdl7vuzFyEc0c-E3AWR2wxy2HrwG9KaFpIhD130q1Lia_9O1w6PCdyK0IllAL4AWQq7NMolpSNCLpc5hasZt5MwHxWZCn1wLnw9lkRiWgZYEI74y-dR4NPHzKSEOjOsgJ2XZsEPzmYiel12NWupip7gdjf9GXR" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="193" data-original-width="241" height="160" src="https://blogger.googleusercontent.com/img/a/AVvXsEgbGZbd7t4JvY4ZwpGSAYjuLKqCuODdl7vuzFyEc0c-E3AWR2wxy2HrwG9KaFpIhD130q1Lia_9O1w6PCdyK0IllAL4AWQq7NMolpSNCLpc5hasZt5MwHxWZCn1wLnw9lkRiWgZYEI74y-dR4NPHzKSEOjOsgJ2XZsEPzmYiel12NWupip7gdjf9GXR=w200-h160" width="200" /></a></div><br />So, no duplicates from both tables must be present in the merged table myDetailsTmp.<p></p><p><br /></p><p>This is how you can achieve it. </p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Process report data.</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">processReport</span>()
{
Query query;
QueryRun qr;
myDetails details;
LedgerJournalTrans trans;
ProjId prevProjId;
<span style="color: #888888;">// merge trans and detail even if details are empty</span>
<span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">insertWithTrans</span>()
{
myDetailsTmp.clear();<br /> myDetailsTmp.RefRecId = trans.RecId;<br /> myDetailsTmp.JournalNum = trans.JournalNum;<br /> myDetailsTmp.TransDate = trans.TransDate;<br /> myDetailsTmp.Voucher = trans.Voucher;<br /> myDetailsTmp.ProjId = trans.mgcProjId;<br /> myDetailsTmp.DetailId = details.DetailId;<br /> myDetailsTmp.WithPrice = details.WithPrice;<br />
myDetailsTmp.insert();<br /> }
<span style="color: #888888;">// merge empty trans and detail; it will be 'a hanging' detail</span>
<span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">insertDetails</span>()
{
myDetailsTmp.clear();<br /> myDetailsTmp.ProjId = details.ProjId;<br /> myDetailsTmp.DetailId = details.DetailId;<br /> myDetailsTmp.WithPrice = details.WithPrice;<br />
myDetailsTmp.insert();<br /> }
<span style="color: #888888;">// process warrants for the previous projId</span>
<span style="color: #888888;">// 'hanging' details on the right side of the report</span>
<span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">processRestOfDetails</span>()
{
<span style="color: #888888;">// if there are still some warrants we found for the previous projId</span>
<span style="color: #008800; font-weight: bold;">if</span> (details)
{
<span style="color: #888888;">// as we do not have enough rows from trans with the same previous projId,</span>
<span style="color: #888888;">// let's add them with empty part from trans side</span>
next details;
<span style="color: #008800; font-weight: bold;">while</span>(details)
{
insertWarrants();
next details;
}
}
}
<span style="color: #888888;">// Get the query from the runtime using a dynamic query.</span>
query = <span style="color: #008800; font-weight: bold;">this</span>.parmQuery();
qr = <span style="color: #008800; font-weight: bold;">new</span> QueryRun(query);
<span style="color: #888888;">// we suppose that trans sorted by projId</span>
<span style="color: #888888;">// each projId may have 0..N of warrants (details)</span>
<span style="color: #008800; font-weight: bold;">while</span>(qr.next())
{
<span style="color: #888888;">// get next transaction</span>
trans = qr.<span style="color: #008800; font-weight: bold;">get</span>(tablenum(LedgerJournalTrans));
<span style="color: #888888;">// projId changes </span>
<span style="color: #008800; font-weight: bold;">if</span>(prevProjId != trans.mgcProjId)
{
<span style="color: #888888;">// if there are still some warrants we found for the previous projId</span>
processRestOfDetails();
<span style="color: #888888;">// get the first warrant for the new projId </span>
<span style="color: #008800; font-weight: bold;">select</span> details
<span style="color: #008800; font-weight: bold;">where</span> details.ProjId == trans.mgcProjId;
<span style="color: #888888;">// keep the new as a previous for the next iteration</span>
prevProjId = trans.mgcProjId;
}
<span style="color: #888888;">// if this is a trans with the same projId, then we can merge it with the next warrant</span>
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #0066bb; font-weight: bold;">if</span> (details)
{
next details;
}
<span style="color: #888888;">// merge trans with warrants</span>
insertWithTrans();
}
<span style="color: #888888;">// if there are still some warrants we found for the previous projId</span>
processRestOfDetails();
}
</pre></div><br /><div>Raw outer joined data</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh97HqOxt1QzEgmA6iNye1Oto9Tk5P_Pse9S69ktKMPHsRlZn-z8o7BVW6fFZQ4h_9eIRBlZgpC-0t7PdcRuTy3LBU0GER-Y1MpzmVB0-kBQJDnP4-xR5BXJBPQuvonCPn6LlHbBueFMwfM69AZlMy4gw856alv16yjM5Q-Cc50kVC6G6Tuo6oEHXBunlI/s1084/2024-02-21_12-18-31.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="311" data-original-width="1084" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh97HqOxt1QzEgmA6iNye1Oto9Tk5P_Pse9S69ktKMPHsRlZn-z8o7BVW6fFZQ4h_9eIRBlZgpC-0t7PdcRuTy3LBU0GER-Y1MpzmVB0-kBQJDnP4-xR5BXJBPQuvonCPn6LlHbBueFMwfM69AZlMy4gw856alv16yjM5Q-Cc50kVC6G6Tuo6oEHXBunlI/w640-h184/2024-02-21_12-18-31.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><br /></div><div>Ascending ProjId</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeOxnX_8OOyonDyksSAGqE02GGdJtBv46XzTFQtcEZm4cPeeGZ-uWMxOBHdvCk0QfOOORJVSb1y-WnA-zlVOo_SCaPGQVrDlly4oMfOq-tSjsltd0gEmAjEaiPqh7puw8o7DTNcF0Qbp9u1aV6ZScaMZMqGgnrSUKgP_0dGHgLXVpUmlVClQzrwd_BMvg/s725/2024-02-21_12-23-35.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="585" data-original-width="725" height="516" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeOxnX_8OOyonDyksSAGqE02GGdJtBv46XzTFQtcEZm4cPeeGZ-uWMxOBHdvCk0QfOOORJVSb1y-WnA-zlVOo_SCaPGQVrDlly4oMfOq-tSjsltd0gEmAjEaiPqh7puw8o7DTNcF0Qbp9u1aV6ZScaMZMqGgnrSUKgP_0dGHgLXVpUmlVClQzrwd_BMvg/w640-h516/2024-02-21_12-23-35.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div>Descending ProjId</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj19l29kn8daSF4lfvAcYNZHydy9ACCCzVyJqfZ5I7CKP7qThgsQ9C8yJluLSt08XsKxowfhr3I23jPW3jV5YCwPGat4DLovMieRLngH3_OZR0-No10ExkftI23LkFJbRKyOYOSR2oJ0lXa-pXmLR0f3vxyXWt_i7yLwKw5tT8UMxGsi1a2I7lFjj1J4c4/s718/2024-02-21_12-22-14.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="583" data-original-width="718" height="520" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj19l29kn8daSF4lfvAcYNZHydy9ACCCzVyJqfZ5I7CKP7qThgsQ9C8yJluLSt08XsKxowfhr3I23jPW3jV5YCwPGat4DLovMieRLngH3_OZR0-No10ExkftI23LkFJbRKyOYOSR2oJ0lXa-pXmLR0f3vxyXWt_i7yLwKw5tT8UMxGsi1a2I7lFjj1J4c4/w640-h520/2024-02-21_12-22-14.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><br /></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-72769275794316812352023-03-10T19:52:00.002-05:002023-03-10T19:52:58.377-05:00How to export/import Tax registration numbers for Vendors<p> D365FO contains a special data entity which can be used for both DMF export/import and also in Excel Add-in, but... </p><p>There is an interesting InnerJoin inside of this data entity, which may be a hurdle for understanding why you still have no records exported; nevertheless, you have some in TaxRegistration table.</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj72qXn1gQm7gfTmtVPGonn0guZcsTLd3_1Ydh9J0aIaqFJdaTFOSlxPJr3SN1qbJDUUzXYrU7e7qaHZ9X5aNSW0SBmMJKSf372-io_BOli61m0QKAOa7G7aL6UcZ977_0_wT2awu-Iz0zzLBh2ECe1L7dSh5B-dpnaT3nhTCId0gFFlUTFVOdGey2y" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="530" data-original-width="817" src="https://blogger.googleusercontent.com/img/a/AVvXsEj72qXn1gQm7gfTmtVPGonn0guZcsTLd3_1Ydh9J0aIaqFJdaTFOSlxPJr3SN1qbJDUUzXYrU7e7qaHZ9X5aNSW0SBmMJKSf372-io_BOli61m0QKAOa7G7aL6UcZ977_0_wT2awu-Iz0zzLBh2ECe1L7dSh5B-dpnaT3nhTCId0gFFlUTFVOdGey2y=s16000" /></a></div><br />In fact, when you create records in Vendor Registration IDs form, it does not tell you about this constraint.<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjpAMn27yqVNoQLMy4Esi2IzZZ3blYOLYwbUuALo0chacwl-yv5xZmnel97-Pnf06FlQmwCXPrWi3RWwqn3QSmOmMlcYBDUJYQj22Ti3GmRFkAxNT_H37x-jzelq59YmdG2NVJznSp9tsyyjqUW9qUmV33-oGQddke7Xx1kybp-EFr0P33hSqB1JV8x" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="496" data-original-width="1367" src="https://blogger.googleusercontent.com/img/a/AVvXsEjpAMn27yqVNoQLMy4Esi2IzZZ3blYOLYwbUuALo0chacwl-yv5xZmnel97-Pnf06FlQmwCXPrWi3RWwqn3QSmOmMlcYBDUJYQj22Ti3GmRFkAxNT_H37x-jzelq59YmdG2NVJznSp9tsyyjqUW9qUmV33-oGQddke7Xx1kybp-EFr0P33hSqB1JV8x=s16000" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiXl_eBwYKCsvpNlvWSB2pAxT8g4tI-wswWxtZ1CDabH3UkerTcjJMoegZWWNww8Z53Pns9x04xvlsolCH3cb-qCgn37ftVUhjY7mYmMG5rmOjkZNBTq4lhtYrd-beactU1L1lH-KyPU49L5NYxk-XwMcD_bDU5ByAb0MJrBCIvXWpZGpTOpoLiUqLR" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="739" data-original-width="1204" src="https://blogger.googleusercontent.com/img/a/AVvXsEiXl_eBwYKCsvpNlvWSB2pAxT8g4tI-wswWxtZ1CDabH3UkerTcjJMoegZWWNww8Z53Pns9x04xvlsolCH3cb-qCgn37ftVUhjY7mYmMG5rmOjkZNBTq4lhtYrd-beactU1L1lH-KyPU49L5NYxk-XwMcD_bDU5ByAb0MJrBCIvXWpZGpTOpoLiUqLR=s16000" /></a></div><br />To get these records exported, you simply need to add it in Registration categories.<p></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiqV7lrSslqXZL4gorwDHDdys45jdEyiDXylFmloF45jzsYBxQXlbWBGJpcF3Y6c5sBvEX0Um1G1a6mT2jgPpgpCajd8yWJOjCvP53bEYhf0YEdz9r1Fu5OMpaL-j10zwbjX_Qy7bllWGr_eZJaBCvHHHDZQWJTzzIHnm_bs23CjeD4ugrjPe93GQqX" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="280" data-original-width="903" src="https://blogger.googleusercontent.com/img/a/AVvXsEiqV7lrSslqXZL4gorwDHDdys45jdEyiDXylFmloF45jzsYBxQXlbWBGJpcF3Y6c5sBvEX0Um1G1a6mT2jgPpgpCajd8yWJOjCvP53bEYhf0YEdz9r1Fu5OMpaL-j10zwbjX_Qy7bllWGr_eZJaBCvHHHDZQWJTzzIHnm_bs23CjeD4ugrjPe93GQqX=s16000" /></a></div><br />and voila!<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhVBhTOGypD6mdmMMNSzjNk1JykszfHweZlAjVLTuqGaffozvtm1pZ6vt4aov79CjmazqJBG6poKoBI9kzUQl9pxy_jsVjVR7XXg9NxW6XWHq6oVfm_Hz6DCKfDsXYSzZ0_DuDeGPOBgaShAHSmYI9PrvxdrHcnGEIyjItHzMEfVyvbpxWFNfzdKnSs" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="540" data-original-width="1888" src="https://blogger.googleusercontent.com/img/a/AVvXsEhVBhTOGypD6mdmMMNSzjNk1JykszfHweZlAjVLTuqGaffozvtm1pZ6vt4aov79CjmazqJBG6poKoBI9kzUQl9pxy_jsVjVR7XXg9NxW6XWHq6oVfm_Hz6DCKfDsXYSzZ0_DuDeGPOBgaShAHSmYI9PrvxdrHcnGEIyjItHzMEfVyvbpxWFNfzdKnSs=s16000" /></a></div><br /><br /><p></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-61277276747966007872023-03-06T14:33:00.003-05:002023-03-06T14:33:39.900-05:00How to open multiple Purchase orders in new browser tabs<p><!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-weight: bold">static</span> <span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">void</span> <span style="color: #0066BB; font-weight: bold">initFromPurchTable</span>(FormDataSource _formDS)
{<span style="color: #FF0000; background-color: #FFAAAA"></span>
PurchTable currentPurchTable;
Browser browser = <span style="color: #008800; font-weight: bold">new</span> Browser();
<span style="color: #008800; font-weight: bold">for</span> (currentPurchTable = _formDS.getFirst(<span style="color: #008800; font-weight: bold">true</span>) ? _formDS.getFirst(<span style="color: #008800; font-weight: bold">true</span>): _formDS.cursor();
currentPurchTable;
currentPurchTable= _formDS.getnext())
{<span style="color: #FF0000; background-color: #FFAAAA"></span>
<span style="color: #333399; font-weight: bold">var</span> generator = <span style="color: #008800; font-weight: bold">new</span> Microsoft.Dynamics.AX.Framework.Utilities.UrlHelper.UrlGenerator();
<span style="color: #333399; font-weight: bold">var</span> currentHost = <span style="color: #008800; font-weight: bold">new</span> System.Uri(UrlUtility::getUrl());
generator.HostUrl = currentHost.GetLeftPart(System.UriPartial::Authority);
generator.Company = curext();
generator.MenuItemName = <span style="color: #FF0000; background-color: #FFAAAA">'</span>PurchTableListPage<span style="color: #FF0000; background-color: #FFAAAA">'</span>;
generator.Partition = getCurrentPartition();
<span style="color: #888888">// repeat this segment for each datasource to filter</span>
<span style="color: #333399; font-weight: bold">var</span> requestQueryParameterCollection = generator.RequestQueryParameterCollection;
requestQueryParameterCollection.AddRequestQueryParameter(
<span style="color: #FF0000; background-color: #FFAAAA">'</span>PurchTable<span style="color: #FF0000; background-color: #FFAAAA">'</span>,
<span style="color: #FF0000; background-color: #FFAAAA">'</span>PurchId<span style="color: #FF0000; background-color: #FFAAAA">'</span>, currentPurchTable.PurchId
);
System.Uri fullURI = generator.GenerateFullUrl();
browser.navigate(fullURI.AbsoluteUri, <span style="color: #008800; font-weight: bold">true</span>);
}<span style="color: #FF0000; background-color: #FFAAAA"></span>
}<span style="color: #FF0000; background-color: #FFAAAA"></span>
</pre></div>
</p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-23419151048812239712022-11-26T18:50:00.003-05:002024-02-21T13:47:14.024-05:00Get Infolog as a string<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Gets infolog content</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns>infolog string</returns></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> str <span style="color: #0066bb; font-weight: bold;">getErrorStr</span>(container _cont)
{
SysInfologEnumerator enumerator;
SysInfologMessageStruct myStruct;
Exception exception;
str error;
enumerator = SysInfologEnumerator::newData(_cont);
<span style="color: #008800; font-weight: bold;">while</span> (enumerator.moveNext())
{
myStruct = <span style="color: #008800; font-weight: bold;">new</span> SysInfologMessageStruct(enumerator.currentMessage());
exception = enumerator.currentException();
error = strfmt(<span style="background-color: #ffaaaa; color: red;">'</span>%<span style="color: #6600ee; font-weight: bold;">1</span> %<span style="color: #6600ee; font-weight: bold;">2</span><span style="background-color: #ffaaaa; color: red;">'</span>, error, myStruct.message());
}
<span style="color: #008800; font-weight: bold;">return</span> error;
}
</pre></div>
<div id="gtx-anchor" style="height: 15.3846px; left: 293.83px; position: absolute; top: 125.721px; visibility: hidden; width: 15.3029px;"></div><div aria-describedby="bubble-4" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: -33px; opacity: 1; top: 151px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-4"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowup" style="left: 293.331px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-84837657108082741702022-10-31T09:50:00.004-04:002022-10-31T09:50:33.137-04:00Code Review<p>Disclaimer: this is just a short recap of what Martin Dráb explained in his article <a href="https://dev.goshoom.net/2012/08/purpose-of-code-reviews/">https://dev.goshoom.net/2012/08/purpose-of-code-reviews/</a>.</p><p><b>Purpose of code reviews</b></p><p></p><ul style="text-align: left;"><li>Internal quality:</li></ul><ol style="text-align: left;"><ol><li>Overall approach – does the code do the right thing by proper means? </li><li>Maintainability/extensibility – are we able to easily extend the solution, fix bugs etc.? </li><li>Testability – are we able to test the code?</li><li>Documentation – are we able to understand why the code was made and what it does?</li><li>Performance – is the design correct from performance perspective? </li></ol></ol><ul style="text-align: left;"><li>Functional testing: Some bugs are much more visible when looking into code</li><li>Knowledge sharing: Discussions between the developer and the reviewer</li></ul><p></p><p><b>Tools</b></p><p></p><ul style="text-align: left;"><li>BP check </li><li>xppbp.exe</li><li>DevOps code review request</li></ul><p></p><p><b>Top 10 issues discovered from Dynamics AX Code Review</b></p><p><a href="https://www.linkedin.com/pulse/top-10-issues-discovered-from-dynamics-ax-code-review-caillet/">https://www.linkedin.com/pulse/top-10-issues-discovered-from-dynamics-ax-code-review-caillet/</a></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-28630778149131702322022-06-29T21:58:00.002-04:002022-06-30T10:10:26.634-04:00Union query for Project transactions<p><b>Union query</b> may be a very efficient and useful option when you need to fetch similar data fields from different tables. A good example of this may be the case when you to gather information about project related transactions as they can be of different types, like, expenses, fees, items, etc. </p><p>Say, we need to render some report collecting all these different types of transaction that can be posted against a given project and group them by a given financial dimension value in <i>Project group</i>. Let's see how <b>Union query</b> can help us.</p><p>In order to better understand the goal, you can take a look to the standard form <i>ProjInvoiceJournal </i>which perfectly explains how all these table relate to each other. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtQsOpmx9aRWMf5sjfcChk5fccCJhV6ba5DggOzDHlPxVnGZc_NxxMdZA7PzLoa-MS5vXeMSB6B-MrK33pKtW5_s0PKO1bnKVkdMk0JzHSSw4vpwhrqAb9T0Xj1Ent8drIskPWAfznrBw30E0Gt18lKvnfqo2sClmaTgJR2BtoukQUDR7G1SPD0vOv/s925/form.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="492" data-original-width="925" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtQsOpmx9aRWMf5sjfcChk5fccCJhV6ba5DggOzDHlPxVnGZc_NxxMdZA7PzLoa-MS5vXeMSB6B-MrK33pKtW5_s0PKO1bnKVkdMk0JzHSSw4vpwhrqAb9T0Xj1Ent8drIskPWAfznrBw30E0Gt18lKvnfqo2sClmaTgJR2BtoukQUDR7G1SPD0vOv/s16000/form.jpg" /></a></div><p>Most of them contain the same set of fields, and we simply need to get some of them into one view to populate by the report data provider.</p><p>So, at the first step, let's create all necessary queries for the source Project transaction related tables. Pick up the first and create a simple query as depicted. </p><p></p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzfJdEkXQ60mNRKCk7PXU6_5BpB_DAO3LQgZP86gYSNMuexgCkxCKaC3yBi8DhGahcXaZq2n1tBCItkEqy8XXnZeluA6yey77BWt91uLmjbhFPKwotQRbAXB5IKO6Mt-tpyYA5IDCb9dUZl6phpV_4Dw4UwyEL3kBZ7gyFRErVLKty5cQfyVJsFCUX/s651/tmxProjInvoiceCostQuery.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="479" data-original-width="651" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzfJdEkXQ60mNRKCk7PXU6_5BpB_DAO3LQgZP86gYSNMuexgCkxCKaC3yBi8DhGahcXaZq2n1tBCItkEqy8XXnZeluA6yey77BWt91uLmjbhFPKwotQRbAXB5IKO6Mt-tpyYA5IDCb9dUZl6phpV_4Dw4UwyEL3kBZ7gyFRErVLKty5cQfyVJsFCUX/s16000/tmxProjInvoiceCostQuery.jpg" /></a></p><p></p><p>Then create a view based on this query. </p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmms7WisI1eY12gUBhIAES1FqSRPr0UU35wh6b2SySeCtTaWzPkV-SLbYzJLQ6NcybVJd1rYguVINSnUhRZN3COlWNJtN01Oqu8cJa4lPBQi9NjWlgY_99wwTLBlA7D2CRlYyrJwHb2lpbzHRvlWh0bsUclXVq8DcOqn14QIEX84WLN0JI5EPxvvlA/s604/tmxProjInvoiceCostView.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="604" data-original-width="598" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmms7WisI1eY12gUBhIAES1FqSRPr0UU35wh6b2SySeCtTaWzPkV-SLbYzJLQ6NcybVJd1rYguVINSnUhRZN3COlWNJtN01Oqu8cJa4lPBQi9NjWlgY_99wwTLBlA7D2CRlYyrJwHb2lpbzHRvlWh0bsUclXVq8DcOqn14QIEX84WLN0JI5EPxvvlA/s16000/tmxProjInvoiceCostView.jpg" /></a></p><p>Then pick up the next and do the same.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOCavJc0-FJz_MarmZvh8NnObsE3v2aeyIvSBTGY8HZj87rc5VczPzoDXbZl6ZgmufZDw6jm3x5YKGn-ING0C5r8jASvuFNGQ4No8KcFVUku5tm8GjAHxbiG9uBsa8HWnEY_90rGCFFZWLxM6bRGFy5frMOKp2lwaIJ7R1_EiFX9e4JVqG26HTh5Qz/s498/ProjInvoiceEmplDetail.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="487" data-original-width="498" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOCavJc0-FJz_MarmZvh8NnObsE3v2aeyIvSBTGY8HZj87rc5VczPzoDXbZl6ZgmufZDw6jm3x5YKGn-ING0C5r8jASvuFNGQ4No8KcFVUku5tm8GjAHxbiG9uBsa8HWnEY_90rGCFFZWLxM6bRGFy5frMOKp2lwaIJ7R1_EiFX9e4JVqG26HTh5Qz/s16000/ProjInvoiceEmplDetail.jpg" /></a></p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGhInBOaTMmfH4asajbnP-bkA0ehkZ2K4JLzKiv8GmHNfMPWSVheATuj3QopSe1WFB5TtZoqM-oogQoot_26xDvMAA62RML7mSwtldy6fQdv5YNfEBR7XbyeCvwsYo3Qg0AUKf-TJScJr253TMpnI4i_Mg7R_-fI9ZgfmJgyo_UVc6Wpjrv0_OgSVh/s603/tmxProjInvoiceEmplView.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="603" data-original-width="556" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGhInBOaTMmfH4asajbnP-bkA0ehkZ2K4JLzKiv8GmHNfMPWSVheATuj3QopSe1WFB5TtZoqM-oogQoot_26xDvMAA62RML7mSwtldy6fQdv5YNfEBR7XbyeCvwsYo3Qg0AUKf-TJScJr253TMpnI4i_Mg7R_-fI9ZgfmJgyo_UVc6Wpjrv0_OgSVh/s16000/tmxProjInvoiceEmplView.jpg" /></a></p><p>Complete these two steps for all necessary transaction types.</p><p>Now you can create a <b>Union query</b> and add all your views together as they have the same set of fields.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDd4jBKiZnkuGeDUBoSJ6OeuH736jWoL64um8hIUSd8IhC-iqSmZDc4vPIcQzs6aWCr6cjqSu2sfFK-NZwuXT-HZgj-ebRm7Yb_CteJnpzaKG3UvGnh8SzdkEl38q7nYuSGlLVg452eY-iSpZgZ8eqZb56WJQvEP1As3f1njpWQ_mX5ih8phttl-RK/s499/tmxProjInvoiceTransUnionQuery.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="499" data-original-width="447" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDd4jBKiZnkuGeDUBoSJ6OeuH736jWoL64um8hIUSd8IhC-iqSmZDc4vPIcQzs6aWCr6cjqSu2sfFK-NZwuXT-HZgj-ebRm7Yb_CteJnpzaKG3UvGnh8SzdkEl38q7nYuSGlLVg452eY-iSpZgZ8eqZb56WJQvEP1As3f1njpWQ_mX5ih8phttl-RK/s16000/tmxProjInvoiceTransUnionQuery.jpg" /></a></p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieELzYJA5m-VzfAWPN0TMW4Sf5-mE7YOzWeAs8ch-JAWp6Xj2SJl9j-zOvJcfjm_UwoKUK0wKp-ndWGvDeqDlT7fJzIMIS5bfrnjMTNQ_d9jjMxqi98vBb8hQZGPbWu2cBuYkd98NHCakbOEDdrC6i0HcHDhxosi7ioQVgvvpIAhV-Ia_LL6TMBbko/s680/tmxProjInvoiceTransUnionQuery_Properties.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="347" data-original-width="680" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieELzYJA5m-VzfAWPN0TMW4Sf5-mE7YOzWeAs8ch-JAWp6Xj2SJl9j-zOvJcfjm_UwoKUK0wKp-ndWGvDeqDlT7fJzIMIS5bfrnjMTNQ_d9jjMxqi98vBb8hQZGPbWu2cBuYkd98NHCakbOEDdrC6i0HcHDhxosi7ioQVgvvpIAhV-Ia_LL6TMBbko/s16000/tmxProjInvoiceTransUnionQuery_Properties.jpg" /></a></p><p>If you need to distinguish them later who is who, say, in computed column methods, you can use <i>unionAllBranchId </i>field, but this is out of the current focus.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtvOHbbkxta4y7hDcozC3Mo8W02Ruat_u7F30LTCB2tCLzXHh5MRSMQNxqD4bZXOcYSOxtGSEVFujbXZh0AErw33-ZD1LJiRffb44Ke228NuX2hXAUxfgRix4-UkER-GGW0Nir32vR7HR-Bdy3GwqNG-4qXDpuRo6X4GP3b_XmOBynAmoO-h3RklAS/s556/tmxProjInvoiceTransUnionView.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="556" data-original-width="493" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtvOHbbkxta4y7hDcozC3Mo8W02Ruat_u7F30LTCB2tCLzXHh5MRSMQNxqD4bZXOcYSOxtGSEVFujbXZh0AErw33-ZD1LJiRffb44Ke228NuX2hXAUxfgRix4-UkER-GGW0Nir32vR7HR-Bdy3GwqNG-4qXDpuRo6X4GP3b_XmOBynAmoO-h3RklAS/s16000/tmxProjInvoiceTransUnionView.jpg" /></a></p><p>Finally you can elaborate it by adding a new view based on the latter with a simple <i>SUM </i>aggregation for <i>Amount </i>field.</p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZBclIO_7BvfKD_sEPv9LMeM0suWlV_c1egYYZrBt6tmxrgsdIOmmETTkGvSK_aykX-3bZnjjVYYlzd1WewQ6-83eZ94dtGpjRfKaj50un8iu7_kEKhN4cLphaqdaYSH06eaNHfpJMuaKRZnOvmtY2A8cTuqL2kuEuKf0jC20G9j8sfKne0b3s6LmP/s635/tmxProjInvoiceTransUnionSumView.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="635" data-original-width="511" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZBclIO_7BvfKD_sEPv9LMeM0suWlV_c1egYYZrBt6tmxrgsdIOmmETTkGvSK_aykX-3bZnjjVYYlzd1WewQ6-83eZ94dtGpjRfKaj50un8iu7_kEKhN4cLphaqdaYSH06eaNHfpJMuaKRZnOvmtY2A8cTuqL2kuEuKf0jC20G9j8sfKne0b3s6LmP/s16000/tmxProjInvoiceTransUnionSumView.jpg" /></a></p><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp2hsClV_qxm6QO_T2iK-GllHUnQaBnNnMgh-nSH_VQktgGKP4oFqYJSaFhlVSqNgPy6Rcsu-RthXLAEp_itf0SmnKZ_3Uwi_fXKOIBtxWTFaHi0ATBPs0HJv3xava00J4cGGhRkZk1dSj_WjFi8LbyEySpXWEmIGuXPusm5M1xEcilP9I-UwbHrY5/s571/tmxProjInvoiceTransUnionSumView_Properties.jpg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="419" data-original-width="571" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp2hsClV_qxm6QO_T2iK-GllHUnQaBnNnMgh-nSH_VQktgGKP4oFqYJSaFhlVSqNgPy6Rcsu-RthXLAEp_itf0SmnKZ_3Uwi_fXKOIBtxWTFaHi0ATBPs0HJv3xava00J4cGGhRkZk1dSj_WjFi8LbyEySpXWEmIGuXPusm5M1xEcilP9I-UwbHrY5/s16000/tmxProjInvoiceTransUnionSumView_Properties.jpg" /></a></p><p>Basically, you achieve your goal with no coding.</p><p>I am not going into details about the whole project, which you can get by this URL <a href="https://github.com/wojzeh/tmxProjectSalesPerSegment">https://github.com/wojzeh/tmxProjectSalesPerSegment</a>. Ping me, if you have any questions.</p><p><br /></p><p>Related topics: </p><h3 class="post-title entry-title" itemprop="name" style="background-color: #e0e0e0; color: #993333; font-family: "Lucida Grande", "Trebuchet MS"; font-size: 16.9px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; letter-spacing: -1px; line-height: normal; margin-top: 0px;"><a href="https://alexvoy.blogspot.com/2019/03/computed-column-for-union-values-from.html" style="color: #993333; text-decoration-line: none;">Computed column for union values from multiple outer joined data sources in view</a></h3>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-10874931134196343422022-06-19T14:24:00.003-04:002022-06-19T14:24:11.633-04:00D365FO: SysMultiTableLookup - dynamic lookups based on multiple tables<p>Yes, guys, sometimes they come back! </p><p>Fourteen years ago <a href="https://www.linkedin.com/in/kashperuk">Vania Kashperuk</a> created a class which became classics: <a href="http://kashperuk.blogspot.com/2008/09/sysmultitableloookup-dynamic-lookups.html">SysMultiTableLookup</a>. It made possible to create lookups based on multiple tables. Some people are still looking for it in vain among the standard classes. So I decided to create a new version of it for D365FO.</p><p>It combines supporting for both <i>lookup </i>and <i>lookupReference </i>methods: <i>performFormLookup</i> and <i>performFormReferenceLookup</i>.</p><p>Vania added a tutorial form to his class, so did I. There is a form in the project, which shows how unbounded form controls can be looked up with fields and display methods from joined tables as well as the case with aggregation and a <i>CustTable </i>data source to demonstrate a lookup for a reference group.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGLnIohPsGI2eRn-Nk5XVZk9nolkHs5CKbnPjRzc66q4L-lSRzN3Fcxn-V6_EAjTy5mn27zqxEMtlXf2uyHnhUwm1bzQO4BWBB9m0XF1QVMo6zcEn4-e3MyqcnnAPxxVXVcVv41lalsMekDme1upPF08G3elEtl9wsF_5f-sTH5kXjx72p-ZBngUWR/s1147/multi1.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="759" data-original-width="1147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGLnIohPsGI2eRn-Nk5XVZk9nolkHs5CKbnPjRzc66q4L-lSRzN3Fcxn-V6_EAjTy5mn27zqxEMtlXf2uyHnhUwm1bzQO4BWBB9m0XF1QVMo6zcEn4-e3MyqcnnAPxxVXVcVv41lalsMekDme1upPF08G3elEtl9wsF_5f-sTH5kXjx72p-ZBngUWR/s16000/multi1.jpg" /></a></div><br /><p><br /></p><p>Take note that I did not implement resolving and have not tested it thoroughly, neither.</p><p>Feel free to use it and elaborate at your own risk. </p><p>The whole project <b>tmxSysMultiTableLookup </b>is here in <a href="https://github.com/wojzeh/tmxSystemTools">https://github.com/wojzeh/tmxSystemTools</a></p><p>The only class is here</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Multi table lookup. D365FO version based on the original by Vanya Kashperuk</span>
<span style="color: #888888;">/// http://kashperuk.blogspot.com/2008/09/sysmultitableloookup-dynamic-lookups.html</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">tmxSysMultiTableLookup</span> extends SysTableLookup
{
FormBuildInt64Control recIdSelectModeControl;
boolean isReference;
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Is reference lookup</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_parm">boolean</param></span>
<span style="color: #888888;">/// <returns>True if Reference</returns></span>
<span style="color: #008800; font-weight: bold;">protected</span> boolean <span style="color: #0066bb; font-weight: bold;">parmIsReference</span>(boolean _parm = isReference)
{
isReference = _parm;
<span style="color: #008800; font-weight: bold;">return</span> isReference;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Places the specified <paramref name="formRun" /> form into the correct lookup selection mode.</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name="formRun"></span>
<span style="color: #888888;">/// The form to be put into lookup selection mode.</span>
<span style="color: #888888;">/// </param></span>
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">setSelectMode</span>(FormRun _formRun)
{
<span style="color: #008800; font-weight: bold;">if</span>(isReference)
{
<span style="color: #008800; font-weight: bold;">if</span> (!recIdSelectModeControl)
{
<span style="color: #008800; font-weight: bold;">throw</span>(error(Error::wrongUseOfFunction(funcname())));
}
_formRun.selectRecordMode(_formRun.control(recIdSelectModeControl.id()));
}
<span style="color: #008800; font-weight: bold;">else</span>
{
super(_formRun);
}
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Constructs <C>tmxSysMultiTableLookup</C> for a formcontrol with a given query</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_callingControl">Target form Reference group control</param></span>
<span style="color: #888888;">/// <param name = "_query">Query</param></span>
<span style="color: #888888;">/// <param name = "_useLookupValue">Use input value</param></span>
<span style="color: #888888;">/// <param name = "_referenceResolver">AmbiguousReferenceResolver</param></span>
<span style="color: #888888;">/// <returns>Instance of <C>tmxSysMultiTableLookup</C></returns></span>
<span style="color: #008800; font-weight: bold;">static</span> tmxSysMultiTableLookup <span style="color: #0066bb; font-weight: bold;">newReferenceParameters</span>(FormReferenceControl _callingControl, Query _query, boolean _useLookupValue = <span style="color: #008800; font-weight: bold;">true</span>)
{
tmxSysMultiTableLookup sysTableLookup = tmxSysMultiTableLookup::construct();
<span style="color: #008800; font-weight: bold;">if</span>(_query.dataSourceCount() < <span style="color: #6600ee; font-weight: bold;">1</span>)
{
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #0066bb; font-weight: bold;">error</span>(<span style="background-color: #fff0f0;">@"Query needs to be defined before building the lookup"</span>);
}
sysTableLookup.parmIsReference(<span style="color: #008800; font-weight: bold;">true</span>);
sysTableLookup.parmQuery(_query);
sysTableLookup.parmCallingControl(_callingControl);
sysTableLookup.parmUseLookupValue(_useLookupValue);
<span style="color: #008800; font-weight: bold;">return</span> sysTableLookup;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Constructs <C>tmxSysMultiTableLookup</C> for a formcontrol with a given query</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_callingControl">Target form control</param></span>
<span style="color: #888888;">/// <param name = "_query">Query</param></span>
<span style="color: #888888;">/// <param name = "_useLookupValue">Use input value</param></span>
<span style="color: #888888;">/// <param name = "_referenceResolver">AmbiguousReferenceResolver</param></span>
<span style="color: #888888;">/// <returns>Instance of <C>tmxSysMultiTableLookup</C></returns></span>
<span style="color: #008800; font-weight: bold;">static</span> tmxSysMultiTableLookup <span style="color: #0066bb; font-weight: bold;">newParameters</span>(FormControl _callingControl, Query _query, boolean _useLookupValue = <span style="color: #008800; font-weight: bold;">true</span>)
{
tmxSysMultiTableLookup sysTableLookup = tmxSysMultiTableLookup::construct();
<span style="color: #008800; font-weight: bold;">if</span>(_query.dataSourceCount() < <span style="color: #6600ee; font-weight: bold;">1</span>)
{
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #0066bb; font-weight: bold;">error</span>(<span style="background-color: #fff0f0;">@"Query needs to be defined before building the lookup"</span>);
}
sysTableLookup.parmQuery(_query);
sysTableLookup.parmCallingControl(_callingControl);
sysTableLookup.parmUseLookupValue(_useLookupValue);
<span style="color: #008800; font-weight: bold;">return</span> sysTableLookup;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Instantiates <C>tmxSysMultiTableLookup</C></span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns>tmxSysMultiTableLookup</returns></span>
<span style="color: #008800; font-weight: bold;">static</span> tmxSysMultiTableLookup <span style="color: #0066bb; font-weight: bold;">construct</span>()
{
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">tmxSysMultiTableLookup</span>();
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Adds form control</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_dataSourceNo">Datasource number in the query</param></span>
<span style="color: #888888;">/// <param name = "_fieldId">Field num</param></span>
<span style="color: #888888;">/// <param name = "_returnItem">Return item</param></span>
<span style="color: #888888;">/// <param name = "_methodName">Method name</param></span>
<span style="color: #888888;">/// <param name = "_label">Label</param></span>
<span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">addLookupControlMulti</span>(<span style="color: #333399; font-weight: bold;">int</span> _dataSourceNo, fieldId _fieldId, boolean _returnItem, str _methodName, str _label)
{
lookupItems += [[_dataSourceNo, _fieldId, _returnItem, _methodName]];
<span style="color: #008800; font-weight: bold;">if</span> (_label)
{
<span style="color: #008800; font-weight: bold;">this</span>.setLabel(_label);
}
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Adds field as form control</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_methodName">Method name</param></span>
<span style="color: #888888;">/// <param name = "_dataSourceNo">Datasource number in the query</param></span>
<span style="color: #888888;">/// <param name = "_label">Label</param></span>
<span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">addLookupMethodMulti</span>(str _methodName, <span style="color: #333399; font-weight: bold;">int</span> _dataSourceNo = <span style="color: #6600ee; font-weight: bold;">1</span>, str _label =<span style="background-color: #fff0f0;">""</span>)
{
<span style="color: #008800; font-weight: bold;">this</span>.addLookupControlMulti(_dataSourceNo, <span style="color: #6600ee; font-weight: bold;">0</span>, <span style="color: #008800; font-weight: bold;">false</span>, _methodName, _label);
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Adds field as form control</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_dataSourceNo">Datasource number in the query</param></span>
<span style="color: #888888;">/// <param name = "_fieldId">Field num</param></span>
<span style="color: #888888;">/// <param name = "_returnItem">Return item</param></span>
<span style="color: #888888;">/// <param name = "_label">Label</param></span>
<span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">addLookupFieldMulti</span>(fieldId _fieldId, <span style="color: #333399; font-weight: bold;">int</span> _dataSourceNo = <span style="color: #6600ee; font-weight: bold;">1</span>, boolean _returnItem = <span style="color: #008800; font-weight: bold;">false</span>, str _label = <span style="background-color: #ffaaaa; color: red;">''</span>)
{
<span style="color: #008800; font-weight: bold;">if</span> (_dataSourceNo > query.dataSourceCount())
{
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #0066bb; font-weight: bold;">error</span>(Error::wrongUseOfFunction(funcName()));
}
<span style="color: #008800; font-weight: bold;">this</span>.addLookupControlMulti(_dataSourceNo, _fieldId, _returnItem, <span style="background-color: #ffaaaa; color: red;">''</span>, _label);
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Chooses LinkType appropriate to JoinMode</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_joinMode">JoinMode</param></span>
<span style="color: #888888;">/// <returns>FormLinkType</returns></span>
<span style="color: #008800; font-weight: bold;">protected</span> FormLinkType <span style="color: #0066bb; font-weight: bold;">joinMode2LinkType</span>(JoinMode _joinMode)
{
<span style="color: #008800; font-weight: bold;">switch</span> (_joinMode)
{
<span style="color: #008800; font-weight: bold;">case</span> JoinMode::InnerJoin:
<span style="color: #008800; font-weight: bold;">return</span> FormLinkType::InnerJoin;
<span style="color: #008800; font-weight: bold;">case</span> JoinMode::OuterJoin:
<span style="color: #008800; font-weight: bold;">return</span> FormLinkType::OuterJoin;
<span style="color: #008800; font-weight: bold;">case</span> JoinMode::ExistsJoin:
<span style="color: #008800; font-weight: bold;">return</span> FormLinkType::ExistJoin;
<span style="color: #008800; font-weight: bold;">case</span> JoinMode::NoExistsJoin:
<span style="color: #008800; font-weight: bold;">return</span> FormLinkType::NotExistJoin;
}
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #0066bb; font-weight: bold;">error</span>(Error::wrongUseOfFunction(funcName()));
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Configures the data source of the lookup form.</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_formBuildDataSource">FormBuildDataSource</param></span>
<span style="color: #888888;">/// <param name = "_queryBuildDataSource">QueryBuildDataSource</param></span>
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">configureLookupDataSourceMulti</span>(FormBuildDataSource _formBuildDataSource, QueryBuildDataSource _queryBuildDataSource)
{
<span style="color: #008800; font-weight: bold;">this</span>.configureLookupDataSource(_formBuildDataSource);
<span style="color: #008800; font-weight: bold;">if</span>(_queryBuildDataSource.embedded()) <span style="color: #888888;">//joined() or level() > 1</span>
{
_formBuildDataSource.linkType(<span style="color: #008800; font-weight: bold;">this</span>.joinMode2LinkType(_queryBuildDataSource.joinMode()));
_formBuildDataSource.joinSource(_queryBuildDataSource.parentDataSource().name());
}
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Builds grid form control</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_formBuildGridControl">FormBuildGridControl</param></span>
<span style="color: #888888;">/// <param name = "_form">Form</param></span>
<span style="color: #888888;">/// <returns>FormBuildGridControl</returns></span>
<span style="color: #008800; font-weight: bold;">protected</span> FormBuildGridControl <span style="color: #0066bb; font-weight: bold;">buildGridMulti</span>(FormBuildGridControl _formBuildGridControl, Form _form)
{
FormBuildDataSource formBuildDataSource;
FormBuildControl formBuildControl;
Object obj;
boolean returnItem;
str method;
<span style="color: #333399; font-weight: bold;">int</span> fieldId;
<span style="color: #333399; font-weight: bold;">int</span> i;
boolean lookupFieldSet = <span style="color: #008800; font-weight: bold;">false</span>;
<span style="color: #333399; font-weight: bold;">int</span> dataSourceNo;
fieldId recIdFieldId;
boolean firstDS = <span style="color: #008800; font-weight: bold;">true</span>;
<span style="color: #888888;">// add fields and display methods for all given data sources</span>
<span style="color: #008800; font-weight: bold;">for</span> (i = <span style="color: #6600ee; font-weight: bold;">1</span>; i <= conlen(lookupItems); i++)
{
<span style="color: #0000cc;"> [dataSourceNo, fieldId, returnItem, method]</span> = conpeek(lookupItems, i);
<span style="color: #008800; font-weight: bold;">if</span>(firstDS)
{
firstDS = <span style="color: #008800; font-weight: bold;">false</span>;
<span style="color: #888888;">// for the reference case</span>
<span style="color: #008800; font-weight: bold;">if</span>(isReference)
{
recIdFieldId = fieldnum(Common, RecId);
<span style="color: #008800; font-weight: bold;">if</span> (recIdFieldId)
{
<span style="color: #888888;">// Always add a hidden RecId control to add as the selectMode field.</span>
recIdSelectModeControl = _formBuildGridControl.addDataField(_form.dataSource(dataSourceNo).id(), recIdFieldId);
recIdSelectModeControl.visible(<span style="color: #008800; font-weight: bold;">false</span>);
}
}
}
<span style="color: #008800; font-weight: bold;">if</span> (fieldId)
{
<span style="color: #888888;">// Add control for a field.</span>
formBuildControl = _formBuildGridControl.addDataField(_form.dataSource(dataSourceNo).id(), fieldId);
}
<span style="color: #008800; font-weight: bold;">else</span>
{
<span style="color: #888888;">// Add control for a display method.</span>
formBuildControl = <span style="color: #008800; font-weight: bold;">this</span>.addMethodControl(_formBuildGridControl, _form.dataSource(dataSourceNo), method, i);
}
<span style="color: #008800; font-weight: bold;">if</span>(!formBuildControl)
{
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #0066bb; font-weight: bold;">error</span>(<span style="background-color: #fff0f0;">"@SYS72176"</span>);
}
<span style="color: #888888;">//</span>
<span style="color: #888888;">// Labels could be specified for both fields and display methods, therefore</span>
<span style="color: #888888;">// they must be checked for every element in lookupItems collection.</span>
<span style="color: #888888;">//</span>
<span style="color: #008800; font-weight: bold;">if</span> (labels[i])
{
obj = formBuildControl;
obj.label(labels[i]);
}
<span style="color: #888888;">//</span>
<span style="color: #888888;">// An index of return field and control must be set according to these rules:</span>
<span style="color: #888888;">// - If return item is specified for a field or a display method, then this field or display method</span>
<span style="color: #888888;">// is considered as the return item.</span>
<span style="color: #888888;">// - If return item is not specified at all, then the first field (but not method) is considered</span>
<span style="color: #888888;">// as the return item.</span>
<span style="color: #888888;">// Currenly too much code is relying on the second rule; therefore it cannot be changed.</span>
<span style="color: #888888;">//</span>
<span style="color: #008800; font-weight: bold;">if</span> (!lookupFieldSet && fieldId <span style="color: #888888;">// If lookup field is not set yet AND current item is a field (not a display method)</span>
|| returnItem) <span style="color: #888888;">// Or if returnItem is explicitly specified for the field or for the display method</span>
{
controlIdx = formBuildControl.id();
lookupField = fieldId;
lookupFieldSet = <span style="color: #008800; font-weight: bold;">true</span>;
}
}
<span style="color: #008800; font-weight: bold;">return</span> _formBuildGridControl;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Constructs the form to use as the lookup form.</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns></span>
<span style="color: #888888;">/// The form to use as the lookup form.</span>
<span style="color: #888888;">/// </returns></span>
<span style="color: #008800; font-weight: bold;">protected</span> FormRun <span style="color: #0066bb; font-weight: bold;">formRun</span>()
{
DictTable dictTable;
DictField dictField;
Form form = <span style="color: #008800; font-weight: bold;">new</span> Form();
FormRun formRun;
FormBuildDesign formBuildDesign;
FormBuildDataSource formBuildDataSource;
FormDataSource formDataSource;
FormBuildGridControl formBuildGridControl;
Args args;
<span style="color: #333399; font-weight: bold;">int</span> idx;
<span style="color: #333399; font-weight: bold;">int</span> i;
FormStringControl callingStringControl;
QueryBuildDataSource queryBuildDataSource;
boolean firstDS = <span style="color: #008800; font-weight: bold;">true</span>;
form.name(identifierstr(TemporaryFormName));
<span style="color: #008800; font-weight: bold;">for</span> (i = <span style="color: #6600ee; font-weight: bold;">1</span>; i <= query.dataSourceCount(); i++)
{
queryBuildDataSource = query.dataSourceNo(i);
formBuildDataSource = form.addDataSource(queryBuildDataSource.name());
formBuildDataSource.table(queryBuildDataSource.table());
<span style="color: #008800; font-weight: bold;">this</span>.configureLookupDataSourceMulti(formBuildDataSource, queryBuildDataSource);
<span style="color: #008800; font-weight: bold;">if</span>(firstDS)
{
firstDS = <span style="color: #008800; font-weight: bold;">false</span>;
<span style="color: #008800; font-weight: bold;">if</span>(isReference)
{
<span style="color: #888888;">// Require that all fields be selected so that Reference Data sources are updated</span>
<span style="color: #888888;">// correctly.</span>
formBuildDataSource.onlyFetchActive(<span style="color: #008800; font-weight: bold;">false</span>);
}
}
}
formBuildDesign = form.addDesign(<span style="background-color: #ffaaaa; color: red;">'</span>Design<span style="background-color: #ffaaaa; color: red;">'</span>);
<span style="color: #008800; font-weight: bold;">this</span>.buildFormDesign(formBuildDesign);
formBuildGridControl = formBuildDesign.addControl(FormControlType::Grid,<span style="background-color: #ffaaaa; color: red;">'</span>Grid<span style="background-color: #ffaaaa; color: red;">'</span>);
formBuildGridControl.dataSource(query.dataSourceNo(<span style="color: #6600ee; font-weight: bold;">1</span>).name());
<span style="color: #008800; font-weight: bold;">this</span>.buildFormGridDesign(formBuildGridControl);
idx = formBuildGridControl.id();
<span style="color: #008800; font-weight: bold;">this</span>.buildGridMulti(formBuildGridControl, form);
<span style="color: #008800; font-weight: bold;">this</span>.buildControlsFinal(formBuildDesign);
<span style="color: #008800; font-weight: bold;">if</span> (lookupField)
{
dictField = <span style="color: #008800; font-weight: bold;">new</span> dictField(tableId, lookupField);
}
args = <span style="color: #008800; font-weight: bold;">new</span> Args();
args.<span style="color: #333399; font-weight: bold;">object</span>(form);
args.callerFormControl(callingControl);
<span style="color: #008800; font-weight: bold;">this</span>.buildArgs(args);
<span style="color: #888888;">//highlighting existing value doesn't work with temp tables</span>
<span style="color: #008800; font-weight: bold;">if</span>(useLookupValue && !tmpBuffer)
{
<span style="color: #888888;">// Let the full kernel-generated lookup process take over.</span>
<span style="color: #008800; font-weight: bold;">if</span> (callingControl <span style="color: #008800; font-weight: bold;">is</span> FormReferenceControl)
{
<span style="color: #008800; font-weight: bold;">if</span> (query != <span style="color: #008800; font-weight: bold;">null</span>)
{
formRun = FormAutoLookupFactory::buildReferenceLookupFromCustomForm(callingControl <span style="color: #008800; font-weight: bold;">as</span> FormReferenceControl, form, args, query);
}
<span style="color: #008800; font-weight: bold;">else</span>
{
formRun = FormAutoLookupFactory::buildReferenceLookupFromCustomForm(callingControl <span style="color: #008800; font-weight: bold;">as</span> FormReferenceControl, form, args);
}
}
<span style="color: #008800; font-weight: bold;">else</span> <span style="color: #0066bb; font-weight: bold;">if</span> (dictField != <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #008800; font-weight: bold;">if</span> (query != <span style="color: #008800; font-weight: bold;">null</span>)
{
formRun = FormAutoLookupFactory::buildLookupFromCustomForm(callingControl, form, AbsoluteFieldBinding::construct(dictField.name(), dictTable.name()), args, query);
}
<span style="color: #008800; font-weight: bold;">else</span>
{
formRun = FormAutoLookupFactory::buildLookupFromCustomForm(callingControl, form, AbsoluteFieldBinding::construct(dictField.name(), dictTable.name()), args);
}
}
<span style="color: #888888;">// The kernel will apply the necessary filter so don't allow this instance to apply a filter</span>
<span style="color: #888888;">// for the lookup control's current value.</span>
skipApplicationOfFilter = <span style="color: #008800; font-weight: bold;">true</span>;
<span style="color: #008800; font-weight: bold;">if</span> (formRun)
{
formDataSource = formRun.dataSource(<span style="color: #6600ee; font-weight: bold;">1</span>);
}
}
<span style="color: #008800; font-weight: bold;">if</span> (formRun == <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #888888;">// Use a watered down lookup that doesn't provide initial positioning.</span>
formRun = classfactory.formRunClass(args);
formRun.init();
formDataSource = formRun.dataSource(<span style="color: #6600ee; font-weight: bold;">1</span>);
<span style="color: #888888;">// Set the custom Query before setting the selectTarget or selectMode</span>
<span style="color: #888888;">// as those methods cause Query normalization logic to be run in the kernel.</span>
<span style="color: #888888;">// (e.g., joins are added as required by the target control).</span>
<span style="color: #008800; font-weight: bold;">if</span> (query)
{
formDataSource.query(query);
}
formRun.selectTarget(<span style="color: #008800; font-weight: bold;">this</span>.parmCallingControl());
}
form = formRun.form();
formGridControl = formRun.control(idx);
formGridControl.setFocus();
<span style="color: #008800; font-weight: bold;">if</span> (tmpBuffer)
{
<span style="color: #008800; font-weight: bold;">if</span> (query.dataSourceCount() > <span style="color: #6600ee; font-weight: bold;">1</span>)
{
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #0066bb; font-weight: bold;">error</span>(<span style="background-color: #fff0f0;">"Multiple temporary datasource lookups are not supported"</span>);
}
formDataSource.init();
<span style="color: #888888;">//BP deviation documented</span>
formDataSource.cursor().setTmp();
formDataSource.cursor().setTmpData(tmpBuffer);
}
<span style="color: #008800; font-weight: bold;">this</span>.setSelectMode(formRun);
<span style="color: #008800; font-weight: bold;">this</span>.buildSelectionListMulti(formDataSource.query());
<span style="color: #008800; font-weight: bold;">this</span>.addFilter(formRun);
<span style="color: #008800; font-weight: bold;">return</span> formRun;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Creates selection list from a given query</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_query">Query</param></span>
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">buildSelectionListMulti</span>(Query _query)
{
boolean returnItem;
str method;
<span style="color: #333399; font-weight: bold;">int</span> fieldId;
<span style="color: #333399; font-weight: bold;">int</span> i;
<span style="color: #333399; font-weight: bold;">int</span> dataSourceNo;
SelectionField <span style="color: #0066bb; font-weight: bold;">fieldKind</span>()
{
<span style="color: #333399; font-weight: bold;">int</span> j;
QueryBuildFieldList qbfl;
qbfl = _query.dataSourceNo(dataSourceNo).fields();
<span style="color: #008800; font-weight: bold;">for</span> (j = <span style="color: #6600ee; font-weight: bold;">1</span>; j <= qbfl.fieldCount(); j++)
{
<span style="color: #008800; font-weight: bold;">if</span> (qbfl.field(j) == fieldId)
{
<span style="color: #008800; font-weight: bold;">return</span> qbfl.fieldKind(j);
}
}
<span style="color: #008800; font-weight: bold;">return</span> SelectionField::Database;
}
<span style="color: #008800; font-weight: bold;">for</span> (i = <span style="color: #6600ee; font-weight: bold;">1</span>; i <= conlen(lookupItems); i++)
{
<span style="color: #0000cc;"> [dataSourceNo, fieldId, returnItem, method]</span> = conpeek(lookupItems, i);
<span style="color: #888888;">// FieldId could be 0 if current element represents a display method used</span>
<span style="color: #888888;">// to return values for a lookup column.</span>
<span style="color: #888888;">// If fieldId is 0 then there is no sense to add it to the selection list of the query.</span>
<span style="color: #008800; font-weight: bold;">if</span> (fieldId)
{
_query.dataSourceNo(dataSourceNo).addSelectionField(fieldId, fieldKind());
}
}
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Obsolete</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_fieldId"></param></span>
<span style="color: #888888;">/// <param name = "_returnItem"></param></span>
<span style="color: #0000cc;"> [SysObsolete('This method is not used for multi table lookup. Use addLookupfieldMulti instead.', true)]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">addLookupfield</span>(FieldId _fieldId, boolean _returnItem = <span style="color: #008800; font-weight: bold;">false</span>)
{
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Obsolete</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_method"></param></span>
<span style="color: #888888;">/// <param name = "_returnItem"></param></span>
<span style="color: #0000cc;"> [SysObsolete('This method is not used for multi table lookup. Use addLookupMethodMulti instead.', true)]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">addLookupMethod</span>(str _method, boolean _returnItem = <span style="color: #008800; font-weight: bold;">false</span>)
{
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Obsolete</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_fieldId"></param></span>
<span style="color: #888888;">/// <param name = "_returnItem"></param></span>
<span style="color: #888888;">/// <param name = "_methodName"></param></span>
<span style="color: #0000cc;"> [SysObsolete('This method is not used for multi table lookup. Use addLookupControlMulti instead.', true)]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">addLookupControl</span>(FieldId _fieldId, boolean _returnItem, str _methodName)
{
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Obsolete</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_formBuildGridControl"></param></span>
<span style="color: #888888;">/// <param name = "_formBuildDataSource"></param></span>
<span style="color: #888888;">/// <returns></returns></span>
<span style="color: #0000cc;"> [SysObsolete('This method is not used for multi table lookup. Use buildGridMulti instead.', true)]</span>
<span style="color: #008800; font-weight: bold;">protected</span> FormBuildGridControl <span style="color: #0066bb; font-weight: bold;">buildGrid</span>(FormBuildGridControl _formBuildGridControl, FormBuildDataSource _formBuildDataSource)
{
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">null</span>;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Obsolete</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_queryBuildDataSource"></param></span>
<span style="color: #0000cc;"> [SysObsolete('This method is not used for multi table lookup. Use buildSelectionListMulti instead.', true)]</span>
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">buildSelectionList</span>(QueryBuildDataSource _queryBuildDataSource)
{
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Presents the lookup form to the user.</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns></span>
<span style="color: #888888;">/// The selected record.</span>
<span style="color: #888888;">/// </returns></span>
<span style="color: #008800; font-weight: bold;">public</span> Common <span style="color: #0066bb; font-weight: bold;">performFormReferenceLookup</span>()
{
FormReferenceControl referenceControl;
FormRun formRun;
Common selectedRecord;
referenceControl = callingControl <span style="color: #008800; font-weight: bold;">as</span> FormReferenceControl;
<span style="color: #008800; font-weight: bold;">if</span> (!referenceControl)
{
<span style="color: #008800; font-weight: bold;">throw</span>(error(Error::wrongUseOfFunction(funcname())));
}
formRun = <span style="color: #008800; font-weight: bold;">this</span>.formRun();
referenceControl.performFormLookup(formRun);
selectedRecord = formRun.selectRecordModeSelectedRecord();
<span style="color: #008800; font-weight: bold;">return</span> selectedRecord;
}
}
</pre></div>
<p></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-76191095175240947412022-06-11T12:10:00.005-04:002022-06-11T12:10:24.663-04:00How to write to an event log from inside of a transaction<p> <!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;">// to write your log from inside of another transaction</span>
<span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">insertExtEventLogInSeparateConnection</span>(RefRecId _lineRecId, str _guid, str _logSource, str _logStr)
{
ExtEventLog log;
UserConnection connection;
<span style="color: #333399; font-weight: bold;">int</span> ttsLevel = appl.ttsLevel(); <span style="color: #888888;">//here you can check if you are inside of a transaction</span>
str errMsg = strFmt(<span style="background-color: #fff0f0;">"Cannot add event log '%1:%2:%3'"</span>, _guid, _logSource, _logStr);
<span style="color: #888888;">// let's create a separate connection</span>
<span style="color: #008800; font-weight: bold;">try</span>
{
connection = <span style="color: #008800; font-weight: bold;">new</span> UserConnection();
connection.ttsbegin();
log.setConnection(connection);
log.InstructionDocLineRecId = _lineRecId;
log.TaskGUID = _guid;
log.LogStr = _logStr;
log.LogSource = _logSource;
log.doInsert();
connection.ttscommit();
}
<span style="color: #008800; font-weight: bold;">catch</span>
{
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #0066bb; font-weight: bold;">error</span>(errMsg);
}
<span style="color: #008800; font-weight: bold;">finally</span>
{
<span style="color: #008800; font-weight: bold;">if</span>(connection)
{
connection.finalize();
}
}
}
</pre></div>
<p></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-46040906851602890162022-05-08T17:35:00.006-04:002024-02-21T13:56:28.406-05:00How to move AX2012 attachment files to SharePoint while upgrading database to D365FO<p><b>Problem</b></p><p>When it comes to upgrading attachments from AX2012 to D365FO, only URLs, notes, and files saved in the former's database may be transferred to the Azure Blob Storage (on-cloud). </p><p>Therefore, all files from attachments in AX2012 should be moved to the database first in order to be successfully migrated to D365FO.</p><p>What if there are millions of them? Technically speaking it might be a good option to save them on SharePoint (on-cloud); however, unfortunately, such attachments links will be deleted, too.</p><p>You can find more detail on Document management in D365FO in <a href="https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/fin-ops/organization-administration/configure-document-management">https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/fin-ops/organization-administration/configure-document-management</a></p><p><b>Technical details</b></p><p>During the Ax2012-D365FO database upgrade process, among other standard classes ('scripts') <i>ReleaseUpdateDB72_Docu</i> is triggered, which actually deletes records in <i>DocuValue</i> and related tables for all files not saved in the data base including even those referenced on a local SharePoint server.</p><p><b>Solution</b></p><p>As a solution we can move all external files referenced in AX2012 attachments to a on-cloud SharePoint server first</p><p>Then an extension to the aforementioned class must be triggered during the standard DB upgrade procedure; so that it would keep existing links and update them accordingly to a new SharePoint folder structure.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA9Xwr4qdynwY8uw3T5DEPtN3-wPqHEYsX6Mu0zrVVfeJjoOsSR6dQY5sE8EavSvy2-0hMPfB14m5IE4pg1PFbAnji6jxg0t29jDhmaQNuFzingOxHs9iySM13RDrgAugIJo-TWTyGv5CU_xzxZ0vI9TcQ3qDhy3Jp29lDLCNq7Dduv2K4msNb_258XE0/s1301/2024-02-21_13-50-23.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="696" data-original-width="1301" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhA9Xwr4qdynwY8uw3T5DEPtN3-wPqHEYsX6Mu0zrVVfeJjoOsSR6dQY5sE8EavSvy2-0hMPfB14m5IE4pg1PFbAnji6jxg0t29jDhmaQNuFzingOxHs9iySM13RDrgAugIJo-TWTyGv5CU_xzxZ0vI9TcQ3qDhy3Jp29lDLCNq7Dduv2K4msNb_258XE0/w640-h342/2024-02-21_13-50-23.jpg" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p><br /></p><p>For example, we can agree that existing local folders will be reproduced on the SharePoint Server instance.</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVVehVm7v5woKvGZ3cZ6A_N54_QK4g9sp9dlyXCSdfTMwSs8CNbx3IhFCQlqVIipmOEHHKXoe1qcJdFJbD_0P2SyZW5P189a9SUbYIRfNmbBbLYnDina6yAg8p6BwbRElJ-VrTdzuq8r3zkCRlIe0MCAj-qmkfQnLsx5F9Hhzv_0Wp4_8k9MyI5LMXPsg/s2002/2024-02-21_13-52-09.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="669" data-original-width="2002" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVVehVm7v5woKvGZ3cZ6A_N54_QK4g9sp9dlyXCSdfTMwSs8CNbx3IhFCQlqVIipmOEHHKXoe1qcJdFJbD_0P2SyZW5P189a9SUbYIRfNmbBbLYnDina6yAg8p6BwbRElJ-VrTdzuq8r3zkCRlIe0MCAj-qmkfQnLsx5F9Hhzv_0Wp4_8k9MyI5LMXPsg/s16000/2024-02-21_13-52-09.jpg" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p>The following code must be adapted accordingly to your landscape and tested first on a small set of files in a dev environment.</p><p>Please, use it at your own risk.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><pre style="background: var(--color-background-container-dark-tint); border-radius: var(--corner-radius-medium); border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: var(--color-text-on-dark); font-family: var(--artdeco-typography-mono); font-size: 16px; line-height: var(--line-height-open); margin-bottom: 3.2rem; margin-top: 3.2rem; overflow-x: auto; padding: 3.2rem; text-wrap: wrap; vertical-align: var(--artdeco-reset-base-vertical-align-baseline);">[ExtensionOf(classStr(ReleaseUpdateDB72_Docu))
final class myReleaseUpdateDB72_Docu_Extension
{
public const str myLegacy = 'Legacy';
public const int myActionClassId = 118; //DocuActionURLClassId
public const str myName = 'Legacy attachments for ';
public const str myHost = 'myCompany.sharepoint.com';
public const str mySite = '/sites/D365FOFileShare';
public const str myUpgradeModifiedUser = 'myAxDocUpgradeUser'; // fake user for marking records
public const int myMaxRowsToUpdatePerStatement = 10000;
public const str myPart1 = "https://myCompany.sharepoint.com/sites/D365FOFileShare/Legacy/";
public const str myPart2 = "https://myCompany.sharepoint.com/sites/D365FOFileShare/_api/Web/GetFileByServerRelativePath(decodedurl=''/sites/D365FOFileShare/Legacy/";
public const str myPart3 = "'')";
public const str myPart4 = "/";
public const str myPart5 = ".";
public const str myPart6 = "''";
/// <summary>
/// Sets a special value to File field to avoid dropping these records by standard script
/// To be run BEFORE the script
/// </summary>
private void myPreUpdateDocuValue_CorrectFileLocations()
{
SysDictTable docuValueTable = new SysDictTable(tableNum(DocuValue));
SysDictTable docuRefTable = new SysDictTable(tableNum(DocuRef));
SysDictTable docuTypeTable = new SysDictTable(tableNum(DocuType));
str sqlQuery;
Connection connection = new Connection();
try
{
int impactedRows;
// First update all DocuValues with null files and empty path
// these files are placed in network shared folders and must be retargeted to SharePoint server
// with setting FILE to a dummy values so that the standard next() won't delete them
do
{
sqlQuery =
strFmt(@"
UPDATE TOP (%8) docValue
SET docValue.%6 = CAST('%1' AS VARBINARY)
FROM %2 docValue
JOIN %3 docRef ON docRef.%7 = docValue.%5
JOIN %11 docType ON (docRef.%12 = docType.%13 and docRef.%14 = docType.%15)
AND docValue.%6 IS NULL AND docValue.%9 ='' AND docValue.%10 = 0 AND docType.%16 = 0",
myUpgradeModifiedUser, // %1 - upgrade modified user
docuValueTable.name(DbBackend::Sql), // %2 - DocuValue
docuRefTable.name(DbBackend::Sql), // %3 - DocuRef
docuValueTable.fieldName(fieldNum(DocuValue, ModifiedBy), DbBackend::Sql), // %4 - DocuValue.ModifiedBy
docuValueTable.fieldName(fieldNum(DocuValue, RecId), DbBackend::Sql), // %5 - DocuValue.RecId
docuValueTable.fieldName(fieldNum(DocuValue, File), DbBackend::Sql), // %6 - DocuValue.File
docuRefTable.fieldName(fieldNum(DocuRef, ValueRecId), DbBackend::Sql), // %7 - DocuRef.ValueRecId
myMaxRowsToUpdatePerStatement, // %8 - Max rows to update per statement
docuValueTable.fieldName(fieldNum(DocuValue, PATH), DbBackend::Sql), // %9 - DocuRef.PATH
docuValueTable.fieldName(fieldNum(DocuValue, Type), DbBackend::Sql), // %10 - DocuValue.Type
docuTypeTable.name(DbBackend::Sql), // %11 - docuTypeTable
docuRefTable.fieldName(fieldNum(DocuRef, TypeId), DbBackend::Sql), // %12 - DocuRef.TypeId
docuTypeTable.fieldName(fieldNum(DocuType, TypeId), DbBackend::Sql), // %13 - DocuType.TypeId
docuRefTable.fieldName(fieldNum(DocuRef,ACTUALCOMPANYID), DbBackend::Sql), // %14 - DocuType.ACTUALCOMPANYID
docuTypeTable.fieldName(fieldNum(DocuType, DATAAREAID), DbBackend::Sql), // %15 - DocuType.DATAAREAID
docuTypeTable.fieldName(fieldNum(DocuType, FILEPLACE), DbBackend::Sql) // %16 - DocuType.FILEPLACE
);
impactedRows = this.myExecuteSQL(sqlQuery, connection);
}
while (impactedRows == myMaxRowsToUpdatePerStatement);
}
finally
{
connection.finalize();
}
}
/// <summary>
/// Nulls FILE field back and updates other field to keep SharePoint links correctly
/// To be run AFTER the script
/// </summary>
private void myPostUpdateDocuValue_CorrectFileLocations()
{
SysDictTable docuValueTable = new SysDictTable(tableNum(DocuValue));
SysDictTable docuRefTable = new SysDictTable(tableNum(DocuRef));
SysDictTable docuTypeTable = new SysDictTable(tableNum(DocuType));
str sqlQuery;
Connection connection = new Connection();
try
{
int impactedRows;
// First update all premarked DocuRef with the new SharePoint docuType
do
{
sqlQuery =
strFmt(@"
UPDATE TOP (%8) docRef
SET
docRef.%17 = '%21' + '_' + docRef.%18
FROM %3 docRef
JOIN %2 docValue ON docRef.%7 = docValue.%5 AND docValue.%6 = CAST('%1' AS VARBINARY) and docRef.%17 <> '%21' + '_' + docRef.%18",
myUpgradeModifiedUser, // %1 - upgrade modified user
docuValueTable.name(DbBackend::Sql), // %2 - DocuValue
docuRefTable.name(DbBackend::Sql), // %3 - DocuRef
docuValueTable.fieldName(fieldNum(DocuValue, Type), DbBackend::Sql), // %4 - DocuValue.Type
docuValueTable.fieldName(fieldNum(DocuValue, RecId), DbBackend::Sql), // %5 - DocuValue.RecId
docuValueTable.fieldName(fieldNum(DocuValue, File), DbBackend::Sql), // %6 - DocuValue.File
docuRefTable.fieldName(fieldNum(DocuRef, ValueRecId), DbBackend::Sql), // %7 - DocuRef.ValueRecId
myMaxRowsToUpdatePerStatement, // %8 - Max rows to update per statement
docuValueTable.fieldName(fieldNum(DocuValue, PATH), DbBackend::Sql), // %9 - DocuRef.PATH
docuValueTable.fieldName(fieldNum(DocuValue, StorageProviderId), DbBackend::Sql), // %10 - DocuRef.StorageProviderId
docuValueTable.fieldName(fieldNum(DocuValue, AccessInformation), DbBackend::Sql), // %11 - DocuRef.AccessInformation
myPart1, // %12 - https://myCompany.sharepoint.com/sites/D365FOFileShare/
myPart2, // %13 - https://myCompany.sharepoint.com/sites/D365FOFileShare/api/Web/GetFileByServerRelativePath(decodedurl='/sites/D365FOFileShare/
myPart3 , // %14 - ')
myPart4 , // %15 - /
myPart5 , // %16 - .
docuRefTable.fieldName(fieldNum(DocuRef, TYPEID), DbBackend::Sql), //%17 - DocuRef.TypeId
docuRefTable.fieldName(fieldNum(DocuRef, ACTUALCOMPANYID), DbBackend::Sql), //%18 - 'SPND'
docuValueTable.fieldName(fieldNum(DocuValue, FILENAME), DbBackend::Sql), // %19 - DocuValue.FILENAME
docuValueTable.fieldName(fieldNum(DocuValue, FILETYPE), DbBackend::Sql), // %20 - DocuValue.FILETYPE
myLegacy // %21 - 'Legacy'
);
impactedRows = this.myExecuteSQL(sqlQuery, connection);
}
while (impactedRows == myMaxRowsToUpdatePerStatement);
impactedRows = 0;
// Now update all premarked DocuValues with new paths and unmark them
do
{
sqlQuery =
strFmt(@"
UPDATE TOP (%8) docValue
SET
docValue.%6 = NULL,
docValue.%4 = 0,
docValue.%10 = 2,
docValue.%9 = '%12'+ docRef.%18 + '%15'+ docValue.%19+'%16' + docValue.%20,
docValue.%11 = '%13'+ + docRef.%18 + '%15'+ docValue.%19+'%16' + docValue.%20 + '%14'
FROM %2 docValue
JOIN %3 docRef ON docRef.%7 = docValue.%5 AND docValue.%6 = CAST('%1' AS VARBINARY)",
//@myPart1 + dr.ACTUALCOMPANYID + @myPart4 + dv.FILENAME+ @myPart5 + dv.FILETYPE
myUpgradeModifiedUser, // %1 - upgrade modified user
docuValueTable.name(DbBackend::Sql), // %2 - DocuValue
docuRefTable.name(DbBackend::Sql), // %3 - DocuRef
docuValueTable.fieldName(fieldNum(DocuValue, Type), DbBackend::Sql), // %4 - DocuValue.Type
docuValueTable.fieldName(fieldNum(DocuValue, RecId), DbBackend::Sql), // %5 - DocuValue.RecId
docuValueTable.fieldName(fieldNum(DocuValue, File), DbBackend::Sql), // %6 - DocuValue.File
docuRefTable.fieldName(fieldNum(DocuRef, ValueRecId), DbBackend::Sql), // %7 - DocuRef.ValueRecId
myMaxRowsToUpdatePerStatement, // %8 - Max rows to update per statement
docuValueTable.fieldName(fieldNum(DocuValue, PATH), DbBackend::Sql), // %9 - DocuRef.PATH
docuValueTable.fieldName(fieldNum(DocuValue, StorageProviderId), DbBackend::Sql), // %10 - DocuRef.StorageProviderId
docuValueTable.fieldName(fieldNum(DocuValue, AccessInformation), DbBackend::Sql), // %11 - DocuRef.AccessInformation
myPart1, // %12 - https://myCompany.sharepoint.com/sites/D365FOFileShare/
myPart2, // %13 - https://myCompany.sharepoint.com/sites/D365FOFileShare/api/Web/GetFileByServerRelativePath(decodedurl='/sites/D365FOFileShare/
myPart3 , // %14 - ')
myPart4 , // %15 - /
myPart5 , // %16 - .
docuRefTable.fieldName(fieldNum(DocuRef, TYPEID), DbBackend::Sql), //%17 - DocuRef.TypeId
docuRefTable.fieldName(fieldNum(DocuRef, ACTUALCOMPANYID), DbBackend::Sql), //%18 - 'SPND'
docuValueTable.fieldName(fieldNum(DocuValue, FILENAME), DbBackend::Sql), // %19 - DocuValue.FILENAME
docuValueTable.fieldName(fieldNum(DocuValue, FILETYPE), DbBackend::Sql), // %20 - DocuValue.FILETYPE
myLegacy // %21 - 'Legacy'
);
impactedRows = this.myExecuteSQL(sqlQuery, connection);
}
while (impactedRows == myMaxRowsToUpdatePerStatement);
}
finally
{
connection.finalize();
}
}
/// <summary>
/// Updates document reference and value records to handle file storage in the cloud.
/// </summary>
[
UpgradeScriptDescription("Updates document value records to handle file storage in the cloud"),
UpgradeScriptStage(ReleaseUpdateScriptStage::PostSync),
UpgradeScriptType(ReleaseUpdateScriptType::PartitionScript),
UpgradeScriptTable(tableStr(DocuRef), false, true, true, false),
UpgradeScriptTable(tableStr(DocuValue), false, true, true, true)
]
public void updateDocuValue_CorrectFileLocations()
{
this.myPreUpdateDocuValue_CorrectFileLocations();
next updateDocuValue_CorrectFileLocations();
this.myPostUpdateDocuValue_CorrectFileLocations();
}
/// <summary>
/// Updates document type records to handle file storage in the cloud.
/// </summary>
[
UpgradeScriptDescription("Updates document type records to handle file storage in the cloud"),
UpgradeScriptStage(ReleaseUpdateScriptStage::PostSync),
UpgradeScriptType(ReleaseUpdateScriptType::PartitionScript),
UpgradeDependsOnTaskAttribute(methodStr(ReleaseUpdateDB72_Docu, updateDocuValue_CorrectFileLocations)),
UpgradeScriptTable(tableStr(DocuType), false, true, true, false)
]
public void updateDocuType_CorrectFilePlacement()
{
next updateDocuType_CorrectFilePlacement();
this.myCreateNewDocuType();
}
/// <summary>
/// Executes the provided SQL statement.
/// </summary>
/// <param name="_sqlStatement">The SQL statement to execute.</param>
/// <param name="_connection>The SQL connection to use; otherwise a new connection will be created.</param>
/// <returns>The number of rows impacted by the statement.</returns>
private int myExecuteSQL(str _sqlStatement, Connection _connection = null)
{
Connection sessionConn = _connection ? _connection : new Connection();
try
{
Statement statement = sessionConn.createStatement();
new SqlStatementExecutePermission(_sqlStatement).assert();
int impactedRows = statement.executeUpdate(_sqlStatement);
statement.close();
CodeAccessPermission::revertAssert();
return impactedRows;
}
finally
{
if (!_connection)
{
sessionConn.finalize();
}
}
}
/// <summary>
/// gets a Set of all legal entities present in the staging
/// </summary>
/// <returns>Set</returns>
public Set getCompanySet()
{
DocuRef docuRef;
Set companySet = new Set(Types::String);
while select ActualCompanyId from docuRef
group by ActualCompanyId
{
companySet.add(docuRef.ActualCompanyId);
}
return companySet;
}
/// <summary>
/// Creates new DocuType records for legacy attachment moved now to SharePoint
/// </summary>
private void myCreateNewDocuType()
{
Set companySet = this.getCompanySet();
SetEnumerator se = companySet.getEnumerator();
DocuType documentType;
ttsbegin;
while (se.MoveNext())
{
SelectableDataArea currCompany = se.current();
changecompany(currCompany)
{
DocuTypeId typeId = myLegacy+'_'+currCompany;
if(!DocuType::exist( typeId))
{
documentType.clear();
documentType.TypeGroup = DocuTypeGroup::File;
documentType.RemoveOption = DocuRemoveOption::DocumentAndFile;
documentType.FileRemovalConfirmation = NoYes::Yes;
documentType.TypeId = typeId;
documentType.ActionClassId = myActionClassId; //DocuActionURLClassId
documentType.Name = myName+currCompany;
documentType.FilePlace = DocuFilePlace::SharePoint;
documentType.Host = myHost;
documentType.Site = mySite;
documentType.FolderPath = myLegacy+'/'+currCompany;
documentType.doInsert();
}
}
}
ttscommit;
}
}]</pre>
</pre></div>
<br /><p></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-22213114286275786312022-04-09T21:22:00.011-04:002024-02-21T14:20:59.176-05:00Multiple company selection in an SSRS report (LedgerLegalEntityLookup)<p>If you need to provide an SSRS report with a multiple company selection, you can opt for a cross-company query. In this case, such an option will be maintained by the system automatically. (You can try this <i>[SrsReportQuery(queryStr(LogisticsEntityLocationUnion))]</i>)</p><p>But what if you need to do that without the former? In this case you'll need to use <i>LedgerLegalEntityLookup </i>class as follows. Say we deal with some mySalesBySegment report, which is meant to return some data for a given selection of legal entities.</p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgiAa3sEQTB_aenmTVOP9fGecX_hL5QG5KtsIqw77J53tByIZqf530KNSiVEEuTa0tqhhlqaj16w7ellHV7ihPlmAhK-SwQroNCSnw6QDhEII9yyJv5HP2FhhUxqXtqdNNktvCpdNJ0eSgy-uZhrwv1lAwEZ8_PoQ1oog5S7XfsiATFIhTCWuUnRdQwsIY" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="735" data-original-width="630" height="400" src="https://blogger.googleusercontent.com/img/a/AVvXsEgiAa3sEQTB_aenmTVOP9fGecX_hL5QG5KtsIqw77J53tByIZqf530KNSiVEEuTa0tqhhlqaj16w7ellHV7ihPlmAhK-SwQroNCSnw6QDhEII9yyJv5HP2FhhUxqXtqdNNktvCpdNJ0eSgy-uZhrwv1lAwEZ8_PoQ1oog5S7XfsiATFIhTCWuUnRdQwsIY=w343-h400" width="343" /></a></div><br /><br /></div><p><br /></p><p>I hid some not relevant code; so that you can get the gist.</p><p>Data contract <i>mySalesBySegmentContract</i>: we keep the user selection of companies as a string.</p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[DataContract]</span>
<span style="color: #0000cc;">[SysOperationContractProcessing(classstr(mySalesBySegmentUIBuilder), SysOperationDataContractProcessingMode::CreateUIBuilderForRootContractOnly)]</span>
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">mySalesBySegmentContract</span> implements SysOperationValidatable
{
...
str legalEntityOptionsStr;
...
<span style="color: #0000cc;"> [</span>
<span style="color: #0000cc;"> DataMember('legalEntityOptions')</span>
<span style="color: #0000cc;"> ,</span>
<span style="color: #0000cc;"> SysOperationGroupMember('Grouping'),</span>
<span style="color: #0000cc;"> SysOperationDisplayOrder('5')</span>
<span style="color: #0000cc;"> ]</span>
<span style="color: #008800; font-weight: bold;">public</span> str <span style="color: #0066bb; font-weight: bold;">parmLegalEntityOptions</span>(str _legalEntityOptions = legalEntityOptionsStr)
{
legalEntityOptionsStr = _legalEntityOptions;
<span style="color: #008800; font-weight: bold;">return</span> legalEntityOptionsStr;
}
}
</pre></div>
<p></p><p>Report controller <i>mySalesBySegmentController</i>: if no companies selected, let's set it to the user's context.</p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">mySalesBySegmentController</span> extends SrsReportRunController
{
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">prePromptModifyContract</span>()
{
mySalesBySegmentContract dc = <span style="color: #008800; font-weight: bold;">this</span>.parmReportContract().parmRdpContract() <span style="color: #008800; font-weight: bold;">as</span> mySalesBySegmentContract;
...
<span style="color: #008800; font-weight: bold;">if</span> (!dc.parmLegalEntityOptions())
{
<span style="color: #888888;">// Set the default value for the legal entity selection</span>
dc.parmLegalEntityOptions(con2str([curExt()]));
}
}
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">preRunModifyContract</span>()
{
mySalesBySegmentContract dc;
container legalEntityOptions;
dc = <span style="color: #008800; font-weight: bold;">this</span>.parmReportContract().parmRdpContract() <span style="color: #008800; font-weight: bold;">as</span> mySalesBySegmentContract;
legalEntityOptions = str2con(dc.parmLegalEntityOptions());
<span style="color: #888888;">// Default current company if there were no company specifications provided to the API.</span>
<span style="color: #008800; font-weight: bold;">if</span> (legalEntityOptions == conNull())
{
legalEntityOptions = [curExt()];
dc.parmLegalEntityOptions(con2str(legalEntityOptions));
}
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">main</span>(Args _args)
{
mySalesBySegmentController controller = <span style="color: #008800; font-weight: bold;">new</span> mySalesBySegmentController();
controller.parmReportName(ssrsReportStr(mySalesBySegment, Report));
controller.parmArgs(_args);
controller.startOperation();
}
}
</pre></div>
<p></p><p>User interface builder <i>mySalesBySegmentUIBuilder</i>: when an SSRS report runs, it shows its dialog twice: the second time in the report viewer, when the report is rendered. Thus we have to override dialog methods in the UIBuilder class to avoid the lovely 'Object reference not set to an instance of an object' error.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">mySalesBySegmentUIBuilder</span> extends SrsReportDataContractUIBuilder
{
mySalesBySegmentContract dc;
<span style="color: #888888;">// Legal entity lookup controls</span>
FormStringControl dialogLegalEntitySelection;
LedgerLegalEntityLookup legalEntityLookup;
<span style="color: #333399; font-weight: bold;">int</span> dialogLegalEntityLookupId;
str userLegalEntityRange;
container legalEntityOptions;
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Override this method in order to initialize the dialog fields after the fields are built.</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">postBuild</span>()
{
DialogField dialogField;
super();
<span style="color: #888888;">// parmCompanySelection</span>
dialogField = <span style="color: #008800; font-weight: bold;">this</span>.bindInfo().getDialogField(<span style="color: #008800; font-weight: bold;">this</span>.dataContractObject(), methodStr(mySalesBySegmentContract, parmLegalEntityOptions));
<span style="color: #008800; font-weight: bold;">this</span>.setInVisible(dialogField);
<span style="color: #008800; font-weight: bold;">this</span>.constructLegalEntityControl(dialog);
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// post runs</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">postRun</span>()
{
super();
<span style="color: #008800; font-weight: bold;">this</span>.constructLegalEntityLookup(dialog);
Set userLegalEntitySet = LedgerSecurityHelper::ledgersWithMinimumSecurityAccess(menuItemActionStr(LedgerExchAdj), AccessRight::Edit, MenuItemType::Action);
userLegalEntityRange = LedgerLegalEntityLookup::getLegalEntityRangeFromLegalEntitySet(userLegalEntitySet);
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Contstruct</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_dialog">Dialog</param></span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">constructLegalEntityControl</span>(Dialog _dialog)
{
FormBuildGroupControl currentGroup = _dialog.form().design().control(_dialog.curFormGroup().name());
FormBuildStringControl dialogLegalEntityLookup = currentGroup.addControl(FormControlType::String, <span style="background-color: #ffaaaa; color: red;">'</span>LegalEntityLookup<span style="background-color: #ffaaaa; color: red;">'</span>);
dialogLegalEntityLookup.extendedDataType(extendedTypeNum(LedgerLegalEntitySelection));
dialogLegalEntityLookup.lookupOnly(<span style="color: #008800; font-weight: bold;">true</span>);
dialogLegalEntityLookupId = dialogLegalEntityLookup.id();
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Constructs the lookup for the legal entity selection.</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_control">The <c>FormStringControl</c> object.</param></span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">legalEntityLookup</span>(FormStringControl _control)
{
legalEntityLookup.lookup(_control.text(), userLegalEntityRange);
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Lookup override</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_dialog">dialog</param></span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">constructLegalEntityLookup</span>(Dialog _dialog)
{
dialoglegalEntitySelection = _dialog.formRun().design().control(dialogLegalEntityLookupId);
legalEntityLookup = LedgerLegalEntityLookup::construct(_dialog.formRun(), dialoglegalEntitySelection);
<span style="color: #888888;">// populates it from the packed paramater</span>
legalEntityLookup.setSelection(str2con(dc.parmLegalEntityOptions()));
<span style="color: #888888;">// let's have our own lookup</span>
dialoglegalEntitySelection.registerOverrideMethod(methodstr(FormStringControl, lookup), methodstr(mySalesBySegmentUIBuilder, legalEntityLookup), <span style="color: #008800; font-weight: bold;">this</span>);
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// prebuilds</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">preBuild</span>()
{
dc = <span style="color: #008800; font-weight: bold;">this</span>.dataContractObject() <span style="color: #008800; font-weight: bold;">as</span> mySalesBySegmentContract;
super();
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Gets it back from the dialog</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">getFromDialog</span>()
{
super();
dc.parmLegalEntityOptions(con2Str(legalEntityLookup.getLegalEntitySelection()));
}
}
</pre></div>
<p></p><p>Report data provider <i>mySalesBySegmentDP</i>: we need just to convert the saved string back to a container, then we can loop through it as required by the report logic.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[SRSReportParameterAttribute(classStr(mySalesBySegmentContract))]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">mySalesBySegmentDP</span> extends SRSReportDataProviderPreProcessTempDB
{
container legalEntityOptions;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">processReport</span>()
{
mySalesBySegmentContract dc;
List legalEntityList;
ListEnumerator legalEntityListEnumerator;
SelectableDataArea companyId;
str companyName;
dc = <span style="color: #008800; font-weight: bold;">this</span>.parmDataContract() <span style="color: #008800; font-weight: bold;">as</span> mySalesBySegmentContract;
<span style="color: #008800; font-weight: bold;">this</span>.setUserConnection(tmp);
<span style="color: #888888;">// getting all selected companies from the report query</span>
legalEntityList = con2List(str2con(dc.parmLegalEntityOptions()));
legalEntityListEnumerator = legalEntityList.getEnumerator();
<span style="color: #008800; font-weight: bold;">while</span> (legalEntityListEnumerator.moveNext())
{
companyId = legalEntityListEnumerator.current();
companyName = CompanyInfo::findDataArea(companyId).name();
changecompany(companyId)
{
<span style="color: #888888;">// Populate the base processing table with data from the appropriate source table</span>
...
}
}
}
}
</pre></div>
<p></p><div id="gtx-anchor" style="height: 30.7692px; left: 7.99947px; position: absolute; top: 152.818px; visibility: hidden; width: 659.667px;"></div><div aria-describedby="bubble-3" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: 4px; opacity: 1; top: 194px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-3"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowup" style="left: 330px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-7323436732768078352022-04-08T11:30:00.004-04:002022-04-08T11:30:32.807-04:00AX World Elephants :)<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3kyFYTpkVM9crIi5hRrbyJQQEu8nY5OW1Cg6a4h6BjjVyYRLju9uCizmQJUAbhLg97iI6FWON2vzZH9LGPQCGQCgzcu6RD6AGrnlo8LIwSSN6-eMi-D3w6vrPo77CfpLQqlRvtZG_BGnnArg3jGKKy1XoGRjUA5avgPAsNjY8Ijd0WBLSrUHL9uSy/s643/3elephants.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="333" data-original-width="643" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3kyFYTpkVM9crIi5hRrbyJQQEu8nY5OW1Cg6a4h6BjjVyYRLju9uCizmQJUAbhLg97iI6FWON2vzZH9LGPQCGQCgzcu6RD6AGrnlo8LIwSSN6-eMi-D3w6vrPo77CfpLQqlRvtZG_BGnnArg3jGKKy1XoGRjUA5avgPAsNjY8Ijd0WBLSrUHL9uSy/s16000/3elephants.jpg" /></a></div><br /><p></p>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-69815743404294413212022-04-04T19:08:00.004-04:002024-02-21T14:23:05.024-05:00How to resolve reference with a form control value<p>If you need not just to maintain lookup for a refence group but also to validate a manually input value, you need to implement <i>resolveReference </i>method for the field of the form data source. Say, we want to validate a custom financial dimension value.</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjwBe844ErKisWVvH4XJrqtHmgVhTLSuFbZo6FdnxuMg4KaftDU-TTZ5GARvOarN37vQ2-26HPNdXHkmA40A4kKZR_ju5JqxlyZ7rl65mQieC-jfxj3wB14q6Ar6pq3JNWvj5qYjyXFvdLte7tMNngA8dbkBAkidLTpKSjJDPYffM_GFdBfkKjr_phRitM" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="182" data-original-width="643" height="182" src="https://blogger.googleusercontent.com/img/a/AVvXsEjwBe844ErKisWVvH4XJrqtHmgVhTLSuFbZo6FdnxuMg4KaftDU-TTZ5GARvOarN37vQ2-26HPNdXHkmA40A4kKZR_ju5JqxlyZ7rl65mQieC-jfxj3wB14q6Ar6pq3JNWvj5qYjyXFvdLte7tMNngA8dbkBAkidLTpKSjJDPYffM_GFdBfkKjr_phRitM=w640-h182" width="640" /></a></div><br /><br /></div><br /><p></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir-faPArU0qS3swmhVGBqGKZ9EutyQMaXYpCYY8hVoxKVV6SsODmZ5KPhY9TlExTjCGw4Cpkawp13NHjbUOnHktYmFwfwHm3PxML1KeEAtpRdLef8TAYOeTjPs79EhZJIPzWAtmSB0bJMNMG-LExq0FjztYiZEPbnp7Cda1x8U9V7q9Kdyv5LokI1b/s1082/resolve2.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="134" data-original-width="1082" height="80" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir-faPArU0qS3swmhVGBqGKZ9EutyQMaXYpCYY8hVoxKVV6SsODmZ5KPhY9TlExTjCGw4Cpkawp13NHjbUOnHktYmFwfwHm3PxML1KeEAtpRdLef8TAYOeTjPs79EhZJIPzWAtmSB0bJMNMG-LExq0FjztYiZEPbnp7Cda1x8U9V7q9Kdyv5LokI1b/w640-h80/resolve2.jpg" width="640" /></a></div><p></p><p>You can check <i>resolveReference*</i> methods in <i>EcoResCategory </i>table as a good example.</p><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2lm5dN9SiCHMNMqNRQwG4vaDIea6HbEJLKn01NeikdjZTsC8_MOlcYBvAtthw2iaQOfgukHhIIE8B2xMi-8mCL7J_ZeBCu2lXkRcX-N2RsbrYx43k_MgrE1Gmj7hRn1AME3vb2NzSiW4X25XobQ_34wwre3v_y5Xo_VXehYPgy_oOwK-1lq1BPxRz/s270/resolve3.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="142" data-original-width="270" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2lm5dN9SiCHMNMqNRQwG4vaDIea6HbEJLKn01NeikdjZTsC8_MOlcYBvAtthw2iaQOfgukHhIIE8B2xMi-8mCL7J_ZeBCu2lXkRcX-N2RsbrYx43k_MgrE1Gmj7hRn1AME3vb2NzSiW4X25XobQ_34wwre3v_y5Xo_VXehYPgy_oOwK-1lq1BPxRz/s1600/resolve3.jpg" width="270" /></a></div><p>The most interesting detail for me is the way how the related form control value is found inside of the given reference group.</p><p></p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> <span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Resolve reference</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <param name = "_formReferenceControl"></param></span>
<span style="color: #888888;">/// <returns></returns></span>
<span style="color: #008800; font-weight: bold;">public</span> Common <span style="color: #0066bb; font-weight: bold;">resolveReference</span>(FormReferenceControl _formReferenceControl)
{
Common ret;
ret = myAssignedBankAccountDimension.dimensionResolveReference(_formReferenceControl);
<span style="color: #008800; font-weight: bold;">return</span> ret;
}
</pre></div>
<br /><p></p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;"> public</span> Common <span style="color: #0066bb; font-weight: bold;">dimensionResolveReference</span>(FormReferenceControl _formReferenceControl)
{
DimensionAttribute dimensionAttribute;
DimensionAttributeDirCategory dimAttributeDirCategory;
DimensionFinancialTag dimensionFinancialTag;
myFinancialDimensionValueFinancialTagView view;
myAssignedBankAccountDimension myAssignedBankAccountDimension;
DimensionDisplayValue dimensionDisplayValue;
<span style="color: #008800; font-weight: bold;">if</span> (!_formReferenceControl || _formReferenceControl.handle() != classNum(FormReferenceGroupControl) )
{
<span style="color: #008800; font-weight: bold;">throw</span>(error(strFmt(<span style="background-color: #fff0f0;">"@SYS137393"</span>, Error::wrongUseOfFunction(funcName())) ));
}
dimensionDisplayValue = <b>_formReferenceControl.filterValue(AbsoluteFieldBinding::construct(fieldStr(DimensionFinancialTag, Value), tableStr(DimensionFinancialTag))).<span style="color: #008800;">value</span>();</b>
dimensionDisplayValue = strLRTrim(dimensionDisplayValue);
<.. implement your logic with the display <span style="color: #008800; font-weight: bold;">value</span> ...>
</pre></div>
<p></p><div id="gtx-anchor" style="height: 15.3846px; left: 384.428px; position: absolute; top: 1107.67px; visibility: hidden; width: 22.4343px;"></div><div aria-describedby="bubble-5" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: 61px; opacity: 1; top: 987px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-5"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowdown" style="left: 387.429px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-58089755821216423352022-04-03T16:25:00.007-04:002024-02-21T14:27:31.949-05:00How to change currency symbol in a given number format<p>Say, we need to print a Vendor payment advice in the vendor's language, whic is <i>es</i> (Spanish) in the example below. Once the report parameter <i>AX_RenderingCulture</i> is set to 'es', all related number formatting will be applied to amounts cells. </p><p>However, the payment may be made in different currencies; thus its currency symbol $ must be used instead of Euro.</p><p></p><div style="text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEicHCV-wXrbIubBRZPtJtyi3TeUWXH23h5HqM8rAP-ZWfMhiT_krQ0gCjqvmzVWV6nWz1dQqQAt5eMULahSWbayRCiWJPf5iaqW487pU5eTPHpxQ6Seqb1yXB4jdYHf11ok5C-m2WoxNLqz63-RsQXWEIJ9Nq5mMMocG3S_PYxK8_WHQBdAUYvMolhk0vk" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="561" data-original-width="841" height="426" src="https://blogger.googleusercontent.com/img/a/AVvXsEicHCV-wXrbIubBRZPtJtyi3TeUWXH23h5HqM8rAP-ZWfMhiT_krQ0gCjqvmzVWV6nWz1dQqQAt5eMULahSWbayRCiWJPf5iaqW487pU5eTPHpxQ6Seqb1yXB4jdYHf11ok5C-m2WoxNLqz63-RsQXWEIJ9Nq5mMMocG3S_PYxK8_WHQBdAUYvMolhk0vk=w640-h426" width="640" /></a></div><br /><br /></div><br /><p></p><p>Basically, such parameters, like currency symbol etc, can be changed through <i><a href="https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo.numberformat?view=net-6.0">System.Globalization.CultureInfo</a></i> class created for the rendering culture. I did not find a way how to achieve it for a particular textbox in SSRS design. So, I formatted the amount directly in X++.</p><p><br /></p><p>I used <i>Global::strFmtByLanguage</i> method as a basis for my method to replace the culture number format currency symbol to a given one. There are a few other interesting methods you can check to see how to deal with formatting dates and numbers.</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> <span style="color: #008800; font-weight: bold;">public</span> str <span style="color: #0066bb; font-weight: bold;">myChangeCurSymbolForAmountStr</span>(LanguageId _languageId, System.Double _amountCur, CurrencySymbol _currencySymbol)
{
System.Globalization.CultureInfo culture;
str res;
System.Exception e;
str curSymbol;
culture = <span style="color: #008800; font-weight: bold;">new</span> System.Globalization.CultureInfo(_languageId);
<span style="color: #008800; font-weight: bold;">try</span>
{
res = _amountCur.ToString(<span style="background-color: #fff0f0;">"C"</span>, culture);
curSymbol = culture.NumberFormat.CurrencySymbol;
res = strReplace(res, curSymbol, _currencySymbol);
}
<span style="color: #008800; font-weight: bold;">catch</span>(Exception::CLRError)
{
e = CLRInterop::getLastException();
<span style="color: #008800; font-weight: bold;">while</span>( e )
{
error( e.get_Message() );
e = e.get_InnerException();
}
<span style="color: #008800; font-weight: bold;">throw</span> Exception::Error;
}
<span style="color: #008800; font-weight: bold;">return</span> res;
}
<span style="color: #008800; font-weight: bold;">public</span> myAmountStringWithCurrencySymbol <span style="color: #0066bb; font-weight: bold;">myAmountStringWithCurrencySymbol</span>(AmountCur _amountCur, CurrencyCode _currency, LanguageId _languageId)
{
Currency currency = Currency::find(_currency);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">this</span>.myChangeCurSymbolForAmountStr(_languageId, _amountCur, currency.Symbol);;
}
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">insertBankPaymAdviceTmp</span>()
{
BankPaymAdviceVendTmp bankPaymAdviceVendTmp;
str email;
next <span style="color: #0066bb; font-weight: bold;">insertBankPaymAdviceTmp</span>();
bankPaymAdviceVendTmp = <span style="color: #008800; font-weight: bold;">this</span>.bankPaymAdviceTmp <span style="color: #008800; font-weight: bold;">as</span> BankPaymAdviceVendTmp;
<span style="color: #008800; font-weight: bold;">if</span> (bankPaymAdviceVendTmp.RecId)
{
ttsbegin;
bankPaymAdviceVendTmp.selectForUpdate(<span style="color: #008800; font-weight: bold;">true</span>);
bankPaymAdviceVendTmp.myBalance01Total+=bankPaymAdviceVendTmp.Balance01;
bankPaymAdviceVendTmp.myAmountStringWithCurrencySymbol = <span style="color: #008800; font-weight: bold;">this</span>.myAmountStringWithCurrencySymbol(bankPaymAdviceVendTmp.EOGBalance01Total, bankPaymAdviceVendTmp.CurrencyCode, VendTable::find(bankPaymAdviceVendTmp.AccountNum).languageId());
bankPaymAdviceVendTmp.update();
ttscommit;
}
}
</pre></div>
<p></p><p>The final string can be referenced in <i>Total </i>textbox as <i>Last(bankPaymAdviceVendTmp.myAmountStringWithCurrencySymbol) </i>and with default format.</p><br /><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiSzT0stMBg-SP1TsiVdrF_DABoNBiDy1eoC84L91CElyWu9XczEYnR5wmaYwrtnJFcTPb0PmjLHe05e6G4UoQlFH58WBDk7FDe-jj-_-vzdaxZ6PGkL5w9e2BMNQFtNab_CGXojbBb4hPzTuAivGVBZnrVYXgXApgPQxYdFslCYwqLgSnFsFm4vd-AOWM" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="554" data-original-width="827" height="428" src="https://blogger.googleusercontent.com/img/a/AVvXsEiSzT0stMBg-SP1TsiVdrF_DABoNBiDy1eoC84L91CElyWu9XczEYnR5wmaYwrtnJFcTPb0PmjLHe05e6G4UoQlFH58WBDk7FDe-jj-_-vzdaxZ6PGkL5w9e2BMNQFtNab_CGXojbBb4hPzTuAivGVBZnrVYXgXApgPQxYdFslCYwqLgSnFsFm4vd-AOWM=w640-h428" width="640" /></a></div><br /><br /></div><br /><p><br /></p><p><br /></p><p><br /></p><div id="gtx-anchor" style="height: 17.9487px; left: 215.385px; position: absolute; top: 1751.51px; visibility: hidden; width: 33.8793px;"></div><div aria-describedby="bubble-11" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: -102px; opacity: 1; top: 1780px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-11"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowup" style="left: 224.372px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-61805000342816707472022-03-17T09:18:00.004-04:002024-02-21T14:29:32.348-05:00Lookup, JumpRef, Modified for a form data source field through CoC<p> As <a class="internal-link view-user-profile" href="https://community.dynamics.com/members/mea_5f00_" style="background: rgb(255, 255, 255); box-sizing: border-box; color: black; font-family: "Segoe UI", SegoeUI, "Segoe UI Web Regular", "Segoe UI Symbol", "Segoe WP", Tahoma, Arial, sans-serif; font-size: 15px; line-height: 20px; outline: 0px; transition: color 0.1s ease 0s;">Ievgen Miroshnikov</a> explained in his old article <a href="https://community.dynamics.com/365/financeandoperations/b/ievgensaxblog/posts/d365foe-how-to-override-form-data-source-field-lookup-method">https://community.dynamics.com/365/financeandoperations/b/ievgensaxblog/posts/d365foe-how-to-override-form-data-source-field-lookup-method</a>, it is much better to override methods directly on a data source field than on its linked form controls.</p><p>I just want to re-iterate it and place here code snippets.</p><p><br /></p><blockquote><ul style="background-color: white; border: 0px; box-sizing: inherit; color: #333a42; font-family: "Noto Serif", Georgia, Times, serif; font-size: 15px; list-style-image: initial; list-style-position: initial; margin: 0px 0px 1.5em 3em; outline: 0px; overflow-wrap: break-word; padding: 0px; vertical-align: baseline;"><li style="border: 0px; box-sizing: inherit; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">User can add new control using form personalization and this control won’t support overridden logic. It could be critical if you are restricting field lookup values or adding validations.</li><li style="border: 0px; box-sizing: inherit; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">One form could have several controls that refers to one data source field so you have to duplicate your code.</li><li style="border: 0px; box-sizing: inherit; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;">Number of delegates are limited as well.</li></ul></blockquote>
So, say we need to implement <i>Lookup</i>, <i>JumpRef</i>, and <i>Modified </i>methods for a custom field on <i>CustInvoiceTable </i>data source of <i>CustFreeInvoice </i>form.
Implement these three aforementioned methods, e.g., directly in an extension to the form class.<div><br />
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(formStr(CustFreeInvoice))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">myCustFreeInvoice_Form_Extension</span>
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">myAssignedBankAccountIdModified</span>(FormDataObject _targetField)
{</pre><pre style="line-height: 125%; margin: 0px;"> <logic>
}
</pre><pre style="line-height: 125%; margin: 0px;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">myAssignedBankAccountIdJumpRef</span>(FormDataObject _targetField)
{</pre><pre style="line-height: 125%; margin: 0px;"><pre style="line-height: 16.25px; margin-bottom: 0px; margin-top: 0px;"> <logic></pre> }
</pre><pre style="line-height: 125%; margin: 0px;"> // Different parameter here!</pre><pre style="line-height: 125%; margin: 0px;"><pre style="line-height: 16.25px; margin-bottom: 0px; margin-top: 0px;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">myAssignedBankAccountIdLookup</span>(FormStringControl _callingControl)
{</pre><pre style="line-height: 16.25px; margin-bottom: 0px; margin-top: 0px;"> <logic>
}</pre></pre></div><div><br /></div>
Now simply override them for the field when the data source is initialized.</div><div>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> m<span style="color: #bb0066; font-weight: bold;">yCustFreeInvoice_Form_EventHandler</span>
{
<span style="color: #0000cc;"> [FormDataSourceEventHandler(formDataSourceStr(CustFreeInvoice, CustInvoiceTable), FormDataSourceEventType::Initialized)]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">myCustInvoiceTable_OnInitialized</span>(FormDataSource _sender, FormDataSourceEventArgs _e)
{
FormRun eogFormRun = _sender.formRun();
FormDataObject eogCustomField = _sender.<span style="color: #333399; font-weight: bold;">object</span>(fieldNum(CustInvoiceTable, eogCustomField));<br />
fdoEOGAssignedBankAccountId.registerOverrideMethod(methodStr(FormDataObject, jumpRef), formMethodStr(CustFreeInvoice, myAssignedBankAccountIdJumpRef), myFormRun);
fdoEOGAssignedBankAccountId.registerOverrideMethod(methodStr(FormDataObject, lookup), formMethodStr(CustFreeInvoice, myAssignedBankAccountIdLookup), myFormRun);
fdoEOGAssignedBankAccountId.registerOverrideMethod(methodStr(FormDataObject, modified), formMethodStr(CustFreeInvoice, myAssignedBankAccountIdModified), myFormRun);
}
</pre></div>
</div><div id="gtx-anchor" style="height: 15.3846px; left: 588.074px; position: absolute; top: 906.01px; visibility: hidden; width: 22.4476px;"></div><div aria-describedby="bubble-12" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: -54px; opacity: 1; top: 785px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-12"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowdown" style="left: 591.075px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0tag:blogger.com,1999:blog-1323778467050606749.post-90706317026797892562022-03-07T12:46:00.006-05:002024-02-21T14:43:51.050-05:00How to populate custom fields in GeneralJournalAccountEntry from LedgerJournalTrans for Ledger, Customer, Vendor, and Bank account type<p> Say, we need to add a new field <i>UniqueId </i>to <i>LedgerJournalTrans </i>and then have it populated in <i>GeneralJournalAccountEntry, </i>once a General journal posted.</p><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhqqmY84VORpNmzFQd_UC4WkYFu7MVyJLcFJngbKYLT4lmtbG4Q4IK7eRUpHa8Tfh4BCTq1dQMtOEEERp-qw7_rjOO2Vmg53w2qJiwuWb5ZbF1yd2f8lhEKgS9T4uF2h6dAllD09xZbKP33kc-c6iHFoqDsqbFlOPh_JpTXx6zj55P-wmh0-LgSivM-B2E" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="525" data-original-width="1170" height="288" src="https://blogger.googleusercontent.com/img/a/AVvXsEhqqmY84VORpNmzFQd_UC4WkYFu7MVyJLcFJngbKYLT4lmtbG4Q4IK7eRUpHa8Tfh4BCTq1dQMtOEEERp-qw7_rjOO2Vmg53w2qJiwuWb5ZbF1yd2f8lhEKgS9T4uF2h6dAllD09xZbKP33kc-c6iHFoqDsqbFlOPh_JpTXx6zj55P-wmh0-LgSivM-B2E=w640-h288" width="640" /></a></div><br /><br /><p></p><p></p><p>In other words the field value must be transferred from a general journal line to a related voucher transaction.</p><p><br /></p><p>Generally speaking there are two different ways how GL transactions created in D365FO: via Source document framework and via <i>LedgerVoucherObject</i>. Moreover, one transaction may be a result of summarization of multiple documents. So, this approach works for this particular scenario, when GL transactions come from a general journal. The proposed solution covers Ledger, Customer, Vendor, and Bank types. You can elaborate it for Project, Fixed Asset, etc. Check their appropriate classes.</p><p><i>LedgerJournalCheckPost </i>class creates one transaction per a line of Ledger type, two if the latter has an offset info.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgHXHjUMMQWekbtItOSMqSdfzJ7vPE-o3eLM5d8DX8jUAkob2zF4zGuYooX2INXM3Ar90SWLwQlvAfFMMHlP4d1N94x4v5k2t_bgHmyeSlHMWCz5qrGpR8gViUeJq0Xza1TJF5Fz4ANRUzkqL8CWvdy0azF-bQtpZLE1ZjXxcuidV-sEEjIh-bhC4Kgy28" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="274" data-original-width="1118" height="156" src="https://blogger.googleusercontent.com/img/a/AVvXsEgHXHjUMMQWekbtItOSMqSdfzJ7vPE-o3eLM5d8DX8jUAkob2zF4zGuYooX2INXM3Ar90SWLwQlvAfFMMHlP4d1N94x4v5k2t_bgHmyeSlHMWCz5qrGpR8gViUeJq0Xza1TJF5Fz4ANRUzkqL8CWvdy0azF-bQtpZLE1ZjXxcuidV-sEEjIh-bhC4Kgy28=w640-h156" width="640" /></a></div><br /><br /><p></p><p>When it comes to other transaction type, first, a transaction in <i>CustTrans</i>, <i>VendTrans</i>, <i>BankTrans </i>etc is created, and then based on the latter a new transaction is added.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgESFrO_FtMMsgKV2MSphmhR-ZVOm-eZ7Iu-TXeryTfQAyveEt3bLovhr61ESaygvXeylAQ5qGWfcvhq2kpA2z7vrV-bRASDDzwi5klrFOMXXFeDb1BLq0zum2wQK6FXQ5N1u744HH-gGLWq54NYP2C53xWMdFjVDNiueKYl0gCe35GZX7XTe-Dz0W8IxA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="393" data-original-width="1719" height="146" src="https://blogger.googleusercontent.com/img/a/AVvXsEgESFrO_FtMMsgKV2MSphmhR-ZVOm-eZ7Iu-TXeryTfQAyveEt3bLovhr61ESaygvXeylAQ5qGWfcvhq2kpA2z7vrV-bRASDDzwi5klrFOMXXFeDb1BLq0zum2wQK6FXQ5N1u744HH-gGLWq54NYP2C53xWMdFjVDNiueKYl0gCe35GZX7XTe-Dz0W8IxA=w640-h146" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjjmy0aAecwhb7YLosn7MDpLu5q_LzjfUyiW77VR5B8_XR7mMW2stub_ySHWUqQVEBG1nL9RYGyrBqQJE7-EEcGhnGHNkoAwgrA0cl4Dtx59NsVDtN5YVEYsW5IVj-rxTjpr4YBrRC8UWs22P3tHZwfttDNoPARk2U4QiiXrNYSjX8gyd1xj8xPGvq9-J0" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="329" data-original-width="1547" height="136" src="https://blogger.googleusercontent.com/img/a/AVvXsEjjmy0aAecwhb7YLosn7MDpLu5q_LzjfUyiW77VR5B8_XR7mMW2stub_ySHWUqQVEBG1nL9RYGyrBqQJE7-EEcGhnGHNkoAwgrA0cl4Dtx59NsVDtN5YVEYsW5IVj-rxTjpr4YBrRC8UWs22P3tHZwfttDNoPARk2U4QiiXrNYSjX8gyd1xj8xPGvq9-J0=w640-h136" width="640" /></a></div><br /><br /><p></p><p>So, we creates the following extensions.</p><p>Tables.</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEid-of9F9XKgNH51V2Rra0iuPvQDrSI-VBvliN3LnrHnsbCETuO_oXoczJKwx2DrRS3Pqh5i5PrWPYP7FVHOq2UkfPaPE6YOWEkx5hIKaw7uLiCOYdR7ZiPbAg_JsWf8llmLvUx-ZnCyS_OR5wEZ-XNOHIqebs0Zl5bti33Ld9roffPRxu2PlGPaZ2R3XI" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="491" data-original-width="242" height="400" src="https://blogger.googleusercontent.com/img/a/AVvXsEid-of9F9XKgNH51V2Rra0iuPvQDrSI-VBvliN3LnrHnsbCETuO_oXoczJKwx2DrRS3Pqh5i5PrWPYP7FVHOq2UkfPaPE6YOWEkx5hIKaw7uLiCOYdR7ZiPbAg_JsWf8llmLvUx-ZnCyS_OR5wEZ-XNOHIqebs0Zl5bti33Ld9roffPRxu2PlGPaZ2R3XI=w197-h400" width="197" /></a></div><br /><br /></div></div></div><br /><p></p><p>Classes.<br /></p><br /><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjmnasXcka_KxTCMe_PI6D1Jl-o2FuPur_NAaDHeAey5E-f7lcz3FtEXlQPrKqzH07t6eLmk6zKdvcmh7_ZguFuEh67jfwch6otC_exf8Ji0-Pcc5__ndhJswaYb6yC1t7rsoc2ROAW-tlP6PosU6l0NKrE6XwL6ONbxpUJ18AXjOOU_qtBdRnijWUqr5Y" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="154" data-original-width="365" height="135" src="https://blogger.googleusercontent.com/img/a/AVvXsEjmnasXcka_KxTCMe_PI6D1Jl-o2FuPur_NAaDHeAey5E-f7lcz3FtEXlQPrKqzH07t6eLmk6zKdvcmh7_ZguFuEh67jfwch6otC_exf8Ji0-Pcc5__ndhJswaYb6yC1t7rsoc2ROAW-tlP6PosU6l0NKrE6XwL6ONbxpUJ18AXjOOU_qtBdRnijWUqr5Y" width="320" /></a></div><br /><br /></div><p>Below, you can find code snippets for each of them.</p><p>BankVoucher_Extension</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(classStr(BankVoucher))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">BankVoucher_Extension</span>
{
<span style="color: #008800; font-weight: bold;">public</span> UniqueId UniqueId;
<span style="color: #008800; font-weight: bold;">public</span> UniqueId p<span style="color: #0066bb; font-weight: bold;">armUniqueId</span>(UniqueId _parm = uniqueId)
{
uniqueId = _parm;
<span style="color: #008800; font-weight: bold;">return</span> uniqueId;
}
<span style="color: #008800; font-weight: bold;">protected</span> LedgerVoucherTransObject <span style="color: #0066bb; font-weight: bold;">initializeLedgerVoucherTransObjectForPosting</span>(LedgerVoucherObject _ledgerVoucherObject, CurrencyExchangeHelper _exchangeRateHelper)
{
LedgerVoucherTransObject ledgerVoucherTransObject = next initializeLedgerVoucherTransObjectForPosting(_ledgerVoucherObject, _exchangeRateHelper);
if(ledgerVoucherTransObject)<br /> {
ledgerVoucherTransObject.parmUniqueId(_ledgerVoucherObject.parmUniqueId());
}
<span style="color: #008800; font-weight: bold;">return</span> ledgerVoucherTransObject;
}
}
</pre></div>
<p>CustVendVoucher_Extension</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(classStr(CustVendVoucher))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">CustVendVoucher_Extension</span>
{
<span style="color: #008800; font-weight: bold;">public</span> UniqueId uniqueId;
</pre><pre style="line-height: 125%; margin: 0px;"> <span style="color: #008800; font-weight: bold;">public</span> UniqueId <span style="color: #0066bb; font-weight: bold;">parmUniqueId</span>(UniqueId _parm = uniqueId)
{
uniqueId = _parm;
<span style="color: #008800; font-weight: bold;">return</span> uniqueId;
}
<span style="color: #008800; font-weight: bold;">protected</span> LedgerVoucherTransObject <span style="color: #0066bb; font-weight: bold;">createLedgerVoucherTransObject</span>(boolean _useSubLedger,
LedgerDimensionAccount _ledgerDimensionMerged,
LedgerJournalTrans _ledgerJournalTrans,
LedgerVoucher _ledgerPostingJournal,
CustVendTrans _custVendTrans)
{
LedgerVoucherTransObject ledgerVoucherTransObject = next createLedgerVoucherTransObject( _useSubLedger, _ledgerDimensionMerged, _ledgerJournalTrans, _ledgerPostingJournal, _custVendTrans);
if(ledgerVoucherTransObject)<br /> {
ledgerVoucherTransObject.parmUniqueId(uniqueId);
}
<span style="color: #008800; font-weight: bold;">return</span> ledgerVoucherTransObject;
}
}
</pre></div>
<p>LedgerJournalCheckPost_Extension</p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(classStr(LedgerJournalCheckPost))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LedgerJournalCheckPost_Extension</span>
{
<span style="color: #008800; font-weight: bold;">protected</span> LedgerVoucherObject <span style="color: #0066bb; font-weight: bold;">createPostingReference</span>(LedgerJournalTrans _ledgerJournalTrans, SysModule _sysModule)
{
LedgerVoucherObject newVoucher = next createPostingReference(_ledgerJournalTrans, _sysModule);
if(newVoucher)<br /> {
newVoucher.parmUniqueId(_ledgerJournalTrans.uniqueId);
}
<span style="color: #008800; font-weight: bold;">return</span> newVoucher;
}
<span style="color: #008800; font-weight: bold;">protected</span> LedgerVoucherObject <span style="color: #0066bb; font-weight: bold;">updatePostingReference</span>(LedgerVoucherObject _postingReference, LedgerJournalTrans _ledgerJournalTrans, SysModule _sysModule)
{
next <span style="color: #0066bb; font-weight: bold;">updatePostingReference</span>(_postingReference, _ledgerJournalTrans, _sysModule);
if(_postingReference)<br /><span> </span><span> {</span>
<span> </span>_postingReference.parmUniqueId(_ledgerJournalTrans.uniqueId);
<span> </span><span> }</span>
<span style="color: #008800; font-weight: bold;">return</span> _postingReference;
}
}
</pre></div>
<p>LedgerJournalTransUpdateBank_Extension</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(classStr(LedgerJournalTransUpdateBank))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LedgerJournalTransUpdateBank_Extension</span>
{
<span style="color: #008800; font-weight: bold;">protected</span> BankVoucher <span style="color: #0066bb; font-weight: bold;">initBankVoucher</span>( LedgerJournalTrans _ledgerJournalTrans,
TaxAmount _taxAmount,
real _taxWithholdAmount,
DimensionDefault _defaultDimension,
LedgerJournalType _ledgerJournalType,
boolean _skipDimensionValidation)
{
BankVoucher bankVoucher = next initBankVoucher(_ledgerJournalTrans, _taxAmount, _taxWithholdAmount, _defaultDimension, _ledgerJournalType, _skipDimensionValidation);
<span> </span><span> if(</span>bankVoucher)<span><br /></span><span> </span><span> {</span>
<span> </span>bankVoucher.parmUniqueId(_ledgerJournalTrans.uniqueId);
<span> </span><span> }</span>
<span style="color: #008800; font-weight: bold;">return</span> bankVoucher;
}
}
</pre></div>
<p>LedgerVoucherObject_Extension</p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(classStr(LedgerVoucherObject))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LedgerVoucherObject_Extension</span>
{
<span style="color: #008800; font-weight: bold;">public</span> UniqueId uniqueId;
<span style="color: #008800; font-weight: bold;">public</span> UniqueId <span style="color: #0066bb; font-weight: bold;">parmUniqueId</span>(UniqueId _parm = uniqueId)
{
uniqueId = _parm;
<span style="color: #008800; font-weight: bold;">return</span> uniqueId;
}
}
</pre></div>
<p>LedgerVoucherTransObject_Extension</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #0000cc;">[ExtensionOf(classStr(LedgerVoucherTransObject))]</span>
final <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LedgerVoucherTransObject_Extension</span>
{
<span style="color: #008800; font-weight: bold;">public</span> UniqueId uniqueId;
<span style="color: #008800; font-weight: bold;">public</span> UniqueId <span style="color: #0066bb; font-weight: bold;">parmUniqueId</span>(UniqueId _parm = uniqueId)
{
generalJournalAccountEntry.UniqueId = _parm;
<span style="color: #008800; font-weight: bold;">return</span> generalJournalAccountEntry.UniqueId;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> LedgerVoucherTransObject <span style="color: #0066bb; font-weight: bold;">newTransLedgerJournal</span>(
LedgerJournalTrans _ledgerJournalTrans,
TaxAmount _taxAmount,
boolean _bridging,
container _intercompanyRecIds,
boolean _reversalsMayExist,
boolean _forcedExchangeRate)
{
LedgerVoucherTransObject ledgerVoucherTransObject = next newTransLedgerJournal(_ledgerJournalTrans, _taxAmount, _bridging, _intercompanyRecIds, _reversalsMayExist, _forcedExchangeRate);
<span> </span><span> if(</span>ledgerVoucherTransObject)<span><br /></span><span> </span><span> {</span>
<span> </span>ledgerVoucherTransObject.parmUniqueId(_ledgerJournalTrans.UniqueId);
<span> </span><span> }</span>
<span style="color: #008800; font-weight: bold;">return</span> ledgerVoucherTransObject;
}
<span style="color: #008800; font-weight: bold;">public</span> LedgerPostingTransactionTmp <span style="color: #0066bb; font-weight: bold;">getLedgerPostingTransaction</span>()
{
LedgerPostingTransactionTmp ledgerPostingTransaction = next getLedgerPostingTransaction();
ledgerPostingTransaction.UniqueId = generalJournalAccountEntry.UniqueId;
<span style="color: #008800; font-weight: bold;">return</span> ledgerPostingTransaction;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">initFromLedgerPostingTransaction</span>(LedgerPostingTransactionTmp _ledgerPostingTransaction,LedgerPostingTransactionProjectTmp _projectPostingTransaction)
{
next <span style="color: #0066bb; font-weight: bold;">initFromLedgerPostingTransaction</span>(_ledgerPostingTransaction,_projectPostingTransaction);
generalJournalAccountEntry.UniqueId = _ledgerPostingTransaction.UniqueId;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> LedgerVoucherTransObject <span style="color: #0066bb; font-weight: bold;">newTransactionAccountingAmountsDefault</span>(
LedgerVoucherObject _defaultLedgerPostingReference,
LedgerPostingType _postingType,
RecId _ledgerDimensionId,
CurrencyCode _transactionCurrencyCode,
Money _transactionCurrencyAmount,
MoneyMST _accountingCurrencyAmount,
CurrencyExchangeHelper _currencyExchangeHelper)
{
LedgerVoucherTransObject postingTrans;
postingTrans = next newTransactionAccountingAmountsDefault(_defaultLedgerPostingReference, _postingType, _ledgerDimensionId, _transactionCurrencyCode, _transactionCurrencyAmount, _accountingCurrencyAmount, _currencyExchangeHelper);
<span> </span><span> if(</span>postingTrans)<span><br /></span><span> </span><span> {</span>
<span> </span>postingTrans.parmUniqueId(_defaultLedgerPostingReference.parmUniqueId());
<span> </span><span> }</span>
<span style="color: #008800; font-weight: bold;">return</span> postingTrans;
}
}
</pre></div>
<p>I wish to credit the following articles I used:</p><p><a href="http://axforum.info/forums/showthread.php?t=74038">http://axforum.info/forums/showthread.php?t=74038</a></p><p><a href="https://allaboutdynamic.com/2018/06/25/d365-ax7-update-custom-fields-in-custtrans-vendtrans-from-ledgerjournaltrans-during-the-posting-of-journal/">https://allaboutdynamic.com/2018/06/25/d365-ax7-update-custom-fields-in-custtrans-vendtrans-from-ledgerjournaltrans-during-the-posting-of-journal/</a></p><p><a href="http://axwiki.blogspot.com/2017/01/customize-field-in-ledgerjournaltabletr.html">http://axwiki.blogspot.com/2017/01/customize-field-in-ledgerjournaltabletr.html</a></p><div id="gtx-anchor" style="height: 15.3846px; left: 513.008px; position: absolute; top: 5320.65px; visibility: hidden; width: 29.579px;"></div><div aria-describedby="bubble-74" class="jfk-bubble gtx-bubble" role="alertdialog" style="left: -125px; opacity: 1; top: 5346px; visibility: visible;"><div class="jfk-bubble-content-id" id="bubble-74"><div id="gtx-host" style="max-width: 400px; min-width: 200px;"></div></div><div aria-label="Close" class="jfk-bubble-closebtn-id jfk-bubble-closebtn" role="button" tabindex="0"></div><div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowup" style="left: 520.008px;"><div class="jfk-bubble-arrowimplbefore"></div><div class="jfk-bubble-arrowimplafter"></div></div></div>wojzehhttp://www.blogger.com/profile/17752044692176547068noreply@blogger.com0