Friday 23 November 2018

Positive pay file in Dynamics 365 F&O



This post demonstrate how to create positive pay file and difference/changes between Dynamics 365 application 7.3 and 8.0. 


      Most of the banks prefer format of the positive pay file in “.txt”. In Dynamics 365 for Finance and Operations, the default format of the Positive Pay file output is XML. Microsoft has provided steps for the setup of Positive pay file as well as a sample XSLT file used to transform the output (7.3 version please see below for 8.0 version XSLT file)

      In 7.3 output file generates as “.xml” and we cannot the change the file extension in the code.
o   If we need the file in “.txt” or other format then we need to save manually “.xml” as “.txt”.
o   Method BankPositivePayExport > getFileExtensionFromURL()  is a private method so we cannot create extensions for private methods.
      Where as in 8.0 and later we can change the file extension to other extensions like “.txt”.
o   Microsoft changed Method BankPositivePayExport > getFileExtensionFromURL()  to protected so we can create extensions and change the file extension.

      In 7.3 the XSLT file accepts the data entity name in whatever way we mention like small letter or capital letter (BankPositivePayExportEntity) and capital letter field names.



      In 8.0 and later version accepts only capital letter data entity name and field names. (BANKPOSITIVEPAYEXPORTENTITY)










Sample XSLT File



<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

  xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl xslthelper"

  xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.02"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xslthelper="http://schemas.microsoft.com/BizTalk/2003/xslthelper"
  xmlns:Message="schemas.microsoft.com/.../Message"
  xmlns:BankPositivePay="schemas.microsoft.com/.../BankPositivePay">
  <xsl:output method="text" omit-xml-declaration="no" version="1.0" encoding="utf-8"/>
  <xsl:template name="last-day-of-month">
    <xsl:param name="date"/>
    <xsl:param name="y" select="substring($date, 1, 4)"/>
    <xsl:param name="m" select="substring($date, 6, 2)"/>
    <xsl:param name="cal" select="'312831303130313130313031'"/>
    <xsl:param name="leap" select="not($y mod 4) and $y mod 100 or not($y mod 400)"/>
    <xsl:param name="month-length" select="substring($cal, 2*($m - 1) + 1, 2) + ($m=2 and $leap)" />
    <xsl:value-of select="concat($y, $m, $month-length)" />
  </xsl:template>
  
  <xsl:template match="/">
    <Document>
      <xsl:for-each select="Document/BANKPOSITIVEPAYEXPORTENTITY">      <!--Cheque Detail begin-->
        <div>
          <xsl:value-of select='"#"'/>          <!--Placeholder-->
          <xsl:value-of select='"SDR"'/>          <!--Payment Method-->
          <xsl:value-of select='"#"'/>
          <xsl:value-of select='"IS"'/>          <!--Service Request Type-->
          <xsl:value-of select='"#"'/>
          <xsl:value-of select="substring(ACCOUNTNUM/text(), 1, 10)"/>          <!--Account Number-->
          <xsl:value-of select='"#"'/>
          <xsl:value-of select='"S"'/>          <!--Single / Range-->
          <xsl:value-of select='"#"'/>
          <xsl:value-of select='"#"'/>          <!--Account Currency-->
          <xsl:value-of select='"#"'/>          <!--Account Name-->
          <xsl:variable name="year" select="substring(TRANSDATE/text(),1,4)" />
          <xsl:variable name="month" select="substring(TRANSDATE/text(),6,2)" />
          <xsl:variable name="day" select="substring(TRANSDATE/text(),9,2)" />
          <xsl:value-of select="concat($year,$month,$day)" />          <!--Issue Date-->
          <xsl:value-of select='"#"'/>
          <xsl:variable name="amount" select="AMOUNTCUR" />
          <xsl:value-of select="format-number($amount, '#.00')" />          <!--Cheque Amount-->
          <xsl:value-of select='"#"'/>
          <xsl:value-of select='normalize-space(CHEQUENUM/text())'/>          <!--Cheque Number-->
          <xsl:value-of select='"#"'/>
          <xsl:value-of select='"#"'/>          <!--Plan Number-->
          <xsl:value-of select='"#"'/>          <!--Additional Data-->
          <xsl:value-of select='BANKNEGINSTRECIPIENTNAME/text()'/>          <!--Issued Payee Name 1-->
          <xsl:value-of select='"#"'/>
            <div>
              <xsl:value-of select='normalize-space(HSRECIPIENTADDRESS/text())'/>
            </div>          <!--Issued Payee Name 2-->
          <xsl:value-of select='"#"'/>
          <xsl:value-of select='"#"'/>          <!--FSI-->
          <xsl:call-template name="last-day-of-month">
            <xsl:with-param name="date" select= 'TRANSDATE'/>            <!--Rule-off Date-->
          </xsl:call-template>
          <xsl:value-of select='"#"'/>
          <xsl:value-of select='"#"'/>          <!--Placeholder-->
          <xsl:value-of select='"#"'/>          <!--Placeholder-->
          <xsl:value-of select='"#"'/>          <!--Duplicate Sequence Number-->
          <xsl:value-of select='"#"'/>          <!--Stop-->
          <xsl:value-of select='"#"'/>          <!--Voided Date-->
          <xsl:value-of select='"#"'/>          <!--Placeholder-->
          <xsl:value-of select='"#"'/>          <!--Placeholder-->
          <xsl:value-of select='"#"'/>          <!--Cents Compare-->
          <xsl:value-of select='"#"'/>          <!--Void-->
          <xsl:value-of select='"#"'/>          <!--Placeholder-->
          <xsl:value-of select='"#"'/>          <!--Comments-->
          <xsl:value-of select='"#"'/>          <!--Payee-->
          <xsl:text>&#xa;</xsl:text>
        </div>
      </xsl:for-each>
    </Document>
  </xsl:template>
</xsl:stylesheet>



Saturday 27 May 2017

Accessing page numbers in SSRS report body

This post demonstrate how to access page numbers in SSRS report body AX 2012/AX 7/ Dynamics 365. 


1. Goto Report à Report Properties à Code in Visual studio

2. Write the below logic in code

Public Function PageNumber() as String
     Dim str as String
     str = Me.Report.Globals!PageNumber.ToString()
     Return str
End Function

Public Function TotalPages() as String
     Dim str as String
     str = Me.Report.Globals!TotalPages.ToString()
     Return str
End Function

3.  Create a text box and the below expression

=Cstr(Code.PageNumber()) & Space(2) & Labels!@SYS26401 & space(2) & Cstr(Code.TotalPages())


4. Example output 1 of 4

Saturday 22 April 2017

Display or edit methods in Dynamics 365 or AX7

New Display or Edit method need to write in extension class.

In the below code is the example for display method in CustTable extension.

[ExtensionOf(tablestr(CustTable))]
final class CustTableEventHandlers_Extension
{
    [SysClientCacheDataMethodAttribute(true)]
    display RetailLoyaltyCardNumber primaryLoyaltyNumber()
    {
        RetailLoyaltyCard   retailLoyaltyCard;

        select firstonly CardNumber from retailLoyaltyCard
            where retailLoyaltyCard.Party == this.party
                && retailLoyaltyCard.Primary == NoYes::Yes;

        return retailLoyaltyCard.CardNumber;
    }
}

After writing logic we need to assign this method to the control in Form.

Set control properties "data method" in the below format

ExtensionClassName::MethodName



Saturday 15 April 2017

Lookups in Dynamics 365 or AX7

Lookups are almost same as AX 2012 but need to write in extension class. Need to copy the event handler and paste in Class and write the same logic as AX 2012.

https://ranjithdax.blogspot.in/2015/01/creation-of-sys-look-in-microsoft.html (AX 2012)

Will get different lookup scenarios one of the scenario is
Scenario: How to filter lookup based on one field value in Dynamics 365.

So 1st  need to get the value of the field value to pass as a range, for that need to get the control value from FORM.

The below code is used to get the filtered lookup based on the other field value.



  [FormControlEventHandler(formControlStr(RetailLoyaltyCards, RetailLoyaltyCard_AuthorizedUser), FormControlEventType::Lookup)]
    public static void RetailLoyaltyCard_AuthorizedUser_OnLookup(FormControl sender, FormControlEventArgs e)
    {
        SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum(DirPartyPostalAddressView), sender);
        QueryBuildDataSource            queryBuildDataSource;
        Query                           query;
        FormRun                         formRun;
        FormControl                     formCtrl;
       
        formRun = sender.formRun();

        formCtrl = formRun.design().controlName(formControlStr(RetailLoyaltyCards, RetailLoyaltyCard_Party2));

        sysTableLookup.addLookupfield(fieldNum(DirPartyPostalAddressView, LocationName), true);
        query = new Query();
        queryBuildDataSource = query.addDataSource(tableNum(DirPartyPostalAddressView));
        queryBuildDataSource.addRange(fieldNum(DirPartyPostalAddressView, Party)).value(SysQuery::value(str2Int64(formCtrl.valueStr())));
          
        sysTableLookup.parmQuery(query);
        sysTableLookup.performFormLookup();
    }




Friday 10 June 2016

Request for the permission of type 'FileIOPermission' failed.


Problem: Generally while working with files we might get the below errors

Request for the permission of type 'FileIOPermission' failed.
(S)\Classes\FileIOPermission\demand
(S)\Classes\WinAPIServer\fileExists- line 11 

or 

Request for the permission of type 'FileIOPermission' failed.
(S)\Classes\FileIOPermission\demand
(S)\Classes\WinAPIServer\deleteFile- line 11 


Solution: 

Set permissionSet;

FileName fileName = ''Test.Xml"; 

permissionSet = new Set(Types::Class);

permissionSet.add(new InteropPermission(InteropKind::ClrInterop));
permissionSet.add(new FileIOPermission(fileName , 'rw'));
CodeAccessPermission::assertMultiple(permissionSet);

 if (WINAPIServer::fileExists(fileName))
    {
        if (Box::yesNo(strfmt("Do you want to re-write the file", filename), DialogButton::No))
        {
            WINAPIServer::deleteFile(filename);
         }
        else
        {
            return;
        }
    }
CodeAccessPermission::revertAssert();

A copy will also require FileIOPermission of 'r' on the source file.  A Move will require a permission of 'w' on the source.

Thursday 9 June 2016

Microsoft.Dynamics.Ax.Xpp.InvalidRemoteCallException’ was thrown


Problem: While working on Files using WinAPI got the below error.

Microsoft.Dynamics.Ax.Xpp.InvalidRemoteCallException’ was thrown


Solution:

Change WinAPI to WinAPIServer

Example:

WINAPI::fileExists(fileName) to WINAPIServer::fileExists(fileName)

WINAPI::deleteFile(filename) to WINAPIServer::deleteFile(filename)