Wednesday 18 July 2018

Large and strange font sizes in menus for Dynamics AX 2012 on remote sessions

Large and strange font sizes in menus for Dynamics AX 2012 on remote sessions

February 14, 2018 at 13:13
filed under Dynamics AX
Tagged 
Hi all!
When you open a Dynamics AX 2012 client (RTM/FP/R2/R3) on a remote session it sometimes looks pretty weird. Font sizes are all over the place and overall it doesn’t look that great. See for example in the following screenshot:
You can get better results by changing the properties of the shortcut if you check the checkbox Disable display scaling on high DPI settings on the Compatibility tab.

The result is better but still not entirely accurate:

You can get the best results by changing the display settings on you host system (so the PC or laptop you are working on). I have Windows 8.1 but you should find a similar setting on other versions of Windows in the Display section of the Control panel.
Microsoft recommends 125% scaling by default, but I prefer to set it at 100%. Setting it to 100% will also give you the best results for Dynamics AX 2012 in remote sessions. So, on your system, change the setting to 100% as seen in the following screenshot.

This property will only be active after you sing off and sign in again, so do that also.
If you connect to a remote session now, you will see that the scaling of the text in Dynamics AX 2012 is now accurate. This will improve your experience and your screenshots.

Empty fields on report

Try below:
Try:1
Some time ago I talked about a problem with SSRS reports that were showing empty fieldswhere data was expected. More recently I talked about how display scaling for high DPI displays can cause fonts in the Dynamics AX client to be all messed up. Today, these two issues kind of had a baby of some kind :).
Apparently, the display sizing setting can cause reports to show empty field when printing to client. When you print to PDF, all data is there. When on your host machine, display sizing is set to 125%, some reports can show empty fields. If you set it to 100%, the problem seems to be solved and the report prints correctly to the screen.
If you are working on multiple monitors, it is possible that it works when your remote desktop sessions is opened on one monitor, but the report shows empty fields when you open your remote on another monitor. As mentioned in the previous post, you also get different results when you change the Disable display scaling on high DPI settings property on the Dynamics AX 2012 shortcut.
In any case, it is best to set the display scaling on the client to 100% if possible to avoid these issues.
Try 2:
At one of our customers, the Open transactions report for customers was not showing data in some of the fields. There should have been amounts on the report but there was just empty space. The weird thing was that this was only happening on PROD and not on ACC or TST.
After some digging, we noticed that the fields that were empty had the Visible property set to Noon the temporary table that was used by the data provider. Thanks to Bill Thompson for pointing us in the right direction: Microsoft Dynamics AX 2012 Report Development Tip – Data Not Showing in Report.
No changes to the report were required, simply set the fields on the temporary table to Visible = Yes and restart the report service. Then the data should show up.
However, although this was a solution, the real problem was that the kernel versions of the AOS and the AX components that were installed on the report server didn’t match. After updating the components to the matching kernel (in our case 6.0.1108.7889-KB3053474-Binary) and restarting the report service, the report worked fine even with the visible property set to No.
So in conclusion, Always check if the kernel versions of all components match when facing weird problems like this.

Anytype : Caution

Anytype is great. It’s a primitive data type can use as a placeholder for any other data type, and comes in handy on many occasions. But don’t use it as a silver bullet, it might backfire.
Consider the next example.
static void AnyType_Test_1(Args _args)
{
    utcDateTime dateTime;
    AnyType     value;
    ;

    value = datetimeutil::utcNow();
    dateTime = value;

    info(strFmt("%1", dateTime));
}
We are assigning the current date and time to the AnyType variable, than back to a utcDateTime, and sending it to te screen. This neatly produces following output:
7/04/2009 19:27:15
Now consider the following example.
static void AnyType_Test_2(Args _args)
{
    utcDateTime dateTime;
    AnyType     value;
    ;

    value = "Here comes today's date";

    value = datetimeutil::utcNow();
    dateTime = value;

    info(strFmt("%1", dateTime));
}
The anytype data types can be automatically converted to dates, enums, integers, reals, strings, guids, int64s, extended data types (records), classes, and containers by assigning a value to the type. […] However, after you have converted the anytype data type, you cannot then change it to another data type.
In the second example it failed to convert the utcDateTime because we assigned a string to the AnyType variable. This is fault very subtle, because no error or warning is shown when compiling such code, and can easily be overlooked.
Not only can (incorrect) use of AnyType cause faulty output, it can also trigger stack traces.
The following example is inspired by Greg.
static void AnyType_Test_3(Args _args)
{
    AnyType     value;
    ;

    value = NoYes::Yes;
    value = datetimeutil::utcNow();
}
This will show the following error message and stack trace:
Error executing code: Wrong argument types in variable assignment.
It gets even nastier in the next example:
static void AnyType_Test_4(Args _args)
{
    utcDateTime dt;
    AnyType value = "string";
    ;

    value = 3;
    dt = value;
}
This will show you a message box saying:
Internal error number 25 in script.
Note: if you are looking to solve the error above (you can encounter it when trying to send an email from code), you can find the links to the hotfixes for ax 2009 here.
And also the error and stack trace we saw before:
Error executing code: Wrong argument types in variable assignment.

Cheque Report

CustVendChequeSlipTextCalculator\fillSlipText  --> where the lines of table are filled.

Thursday 12 July 2018

AX7 Inteview Questions

1.How to create form extensions steps
Right click on form create extension, should on same Model
2.What is COC
3.Number sequence in D365
4.Done any Frame work like Financial dimensions
5.BP for tables
Ladel, Form ref, Index,
What is cache lookup
Lookup to select
==============================================================================
It is a property that helps avoid database access when it’s not strictly necessary. Retrieving database records from memory instead of the database significantly speeds up data access.

Found: If a table is accessed through a primary key or a unique index, the value is cached for the duration of the session or until the record is updated. If another instance of the AOS updates this record, all AOS instances will flush their caches.
This cache setting is appropriate for master data.

NotInTTS:  Works the same way as Found, except that every time a transaction is started, the cache is flushed and the query goes to the database. This cache setting is appropriate for transactional tables.

FoundAndEmpty: Works the same way as Found, except that if the query cannot find a record, the absence of the record is stored. This cache setting is appropriate for region-specific master data or master data that isn’t always present.

EntireTable: The entire table is cached in memory on the AOS, and the client treats this cacheas Found. This cache setting is appropriate for tables with a known number of limited records, such as parameter tables.

None:  No caching occurs. This setting is appropriate in only a few cases, such as when
==============================================================================

Cluster index
Used to fetch data from Index specified
Need to add 4 fields to Grid, filterable and need to loan runtime
Use tmp table, call at run time(init method), add table to DS, add fields
New class to insert data into table
How to write Execute query COC
How you load number seq from production or from front end not using class
Create new RDT,
Write new numRef method at table level
Extend Module class: Load module
New job to load all number sequence
How to extend Execute query method
Use FormDataSourceEventType QueryExecuting to write new extension method
Add Enum above Grid and filter data based on that

Number Sequence in D365

  1. Create new EDT
  2. Add EDT to new table and write below method at table level.
    1. static NumberSequenceReference numRefMROBulkTransferNumber()
      {
      return NumberSeqReference::findReference(extendedTypeNum(MROBulkTransferNumber));
      }
  3. write new class to extend existing module class
    1. [ExtensionOf(classStr(NumberSeqModuleMRO))]
      final class NumberSeqModuleMRO_Extension
      {protected void loadModule()
      {
      NumberSeqDatatype datatype = NumberSeqDatatype::construct();
      next loadModule(); // Execute the augmented original class method
      datatype.parmDatatypeId(extendedtypenum(MROBulkTransferNumber));
      datatype.parmReferenceHelp(literalstr(“Number for Bulk transfer”));
      datatype.parmWizardIsManual(NoYes::No);
      datatype.parmWizardIsChangeDownAllowed(NoYes::No);
      datatype.parmWizardIsChangeUpAllowed(NoYes::No);
      datatype.parmWizardLowest(1);
      datatype.parmWizardHighest(99999999);
      datatype.parmSortField(82);
      datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);
      this.create(datatype);
      }}

  4. Create new Runnable class(Job)
    1. class RunnableClass_numberSeq
      {
      /// <summary>
      /// Runs the class with the specified arguments.
      /// </summary>
      /// <param name = “_args”>The specified arguments.</param>
      public static void main(Args _args)
      {NumberSeqModuleMRO numberSeqMod = new NumberSeqModuleMRO();
      numberSeqMod.load();
      }
      }
  5. To go Organization Administration -> CommonForms -> Numbersequences -> Numbersequences -> Generate -> run the wizard.
  6. Navigate to module(MRO in my case): Setup -> Project management parameters form -> Num Seq.  You will find your new numberSeq

Comma separated Values Method

static void Job(Args _args)
{
   container c;
   str       s;
    ;
   s= "kranthi,kumar,Myname";
   c = str2con(s,",");
conview(c);
}

Chain of Command D365

1) Chain of commands:

It is the new extension possible in AX7. We are able to add pre and post functionality to extensible methods in a much easier and readable manner than the previously used event handlers. We are now able to access protected methods and variables directly in extened clas with out problems.


Create two classes, one is the base class of the other and add a method we want to extend called ‘testMe’. Add infolog calls inside the method to track the execution :
class COCBaseClass
{
void new(){}
protected void testMe()
{
info("base class call");
}
public void runTest()
{
    this.testMe();
}
}

class COCChildClass extends COCBaseClassclass
{
protected void testMe()
{
    info("child class before super");
    super();
    info("child class after super");
}
}
Create a new model, add reference for the class model we created above, and add an extension class for our child class.
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt_Extension
{
protected void testMe()
{
    info("Extension 1 before next call");
    next testMe()
    info("Extension 1 after next call");
}
}
"next” keyword to the call which will wrap our extension code around the extended method. This next keyword separates the pre and post parts of our extension and mandatory to be called inside the chain of command method

Capture1

The advantage of chain of command is you can share the same method variables in the pre and post (before/after next() call) or share the same tts block inside your COC method. COC also supports return value and parameter modification of the extended method in a much more readable manner. Extending a method with return value and parameters in COC is like below :
class COCBaseClass
{
protected int returnMe(int _me)
{
return _me;
}
}
class COCChildClass extends COCBaseClass
{
protected int returnMe(int _me)
{
return super(_me);
}
}
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt_Extension
{
protected int returnMe(int _me)
{
   int ret;
   ret = next returnMe(_me);
   return ret;
}
}
let’s examine some more complex scenarios. Let’s create some other models and add some more chain of command extensions to our testMe method. Here are our two new extension classes in two new models :
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt2_Extension
{
protected void testMe()
{
    info("Extension 2 before next call");
    next testMe()
    info("Extension 2 after next call");
}
}
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt3_Extension
{
protected void testMe()
{
    info("Extension 3 before next call");
    next testMe()
    info("Extension 3 after next call");
}
}
calling all before next () parts of chain of command extension methods, calling the base method, then calling code after the next() calls. :
Capture2
[ExtensionOf(classStr(COCChildClass))]
final class COCChildClassCOCExt2_Extension
{
[PreHandlerFor(classStr(COCChildClass), methodStr(COCChildClass, testMe))]
public static void COCChildClass_Pre_testMe(XppPrePostArgs args)
{
info("Extension 2 pre-eventhandler");
}

[PostHandlerFor(classStr(COCChildClass), methodStr(COCChildClass, testMe))]
public static void COCChildClass_Post_testMe(XppPrePostArgs args)
{
info("Extension 2 post-eventhandler");
}
}
Repeat the same for extension class 3, and run the test again to see the result :
Capture3
As you see the pre and post eventhandlers run after and before the chain of command calls. So chain of command wraps the base method, and its pre and post eventhandlers all together. Just as chain of command, the eventhandler methods are also called in a random order, and not mirrored on pre and post like the chain of command calls
==============================================================================================

HI, From Update12, its possible to write COC for forms as well!
[ExtensionOf(formStr(StageUpdate))] final class StageUpdate_Extension { public void closeOk() {
next closeOk(); Formrun thisForm = @this; FormRun callerForm = thisForm.args().caller();
if( callerForm.name() == formstr(WorkOrderTable))
{
FormDataSource woLineDS = callerForm.dataSource(formDataSourceStr(WorkOrderTable,WorkOrderLine )); WorkOrderLine selectedWOLine = woLineDs.cursor();
}
}

Monday 9 July 2018

Run base Batch Process + D365

Contract : 
[
    DataContractAttribute,
    SysOperationContractProcessingAttribute(classStr(CITCustPaymImportUIBuilder))
]
    class CITCustPaymImportContract implements SysOperationValidatable
{
    CustAccount     custAccount;
    FilePath        filePath;
    FileUpload      filepath1;
    JournalId       journalNum;
    TransDate       postingDate;
    CustGroupId     custGroup;
    [
        //DataMemberAttribute(identifierStr(Filepath)),     
        DataMemberAttribute('Filepath'),
         SysOperationLabelAttribute('Upload document'),
        SysOperationDisplayOrderAttribute('3'),
        SysOperationHelpTextAttribute(literalStr("Assign file path"))
    ]
    public FilePath parmFilePath(FilePath _filePath = filePath)
    {
        filePath = _filePath;
        return filePath;
    }

    [
        //DataMemberAttribute(identifierStr(CustAccount))
        DataMemberAttribute('CustAccount'),
        SysOperationLabelAttribute('Customer Account'),
        SysOperationDisplayOrderAttribute('1'),
        SysOperationHelpTextAttribute(literalStr("Customer Account no."))
    ]
    public CustAccount parmCustAccount(CustAccount _custAccount = custAccount)
    {
        custAccount = _custAccount;
        return custAccount;
    }

    [
        //DataMemberAttribute(identifierStr(JournalNum)),
        DataMemberAttribute('JournalNum'),
        SysOperationControlVisibilityAttribute(false),
        SysOperationDisplayOrderAttribute('4'),
        SysOperationHelpTextAttribute(literalStr("JournalNum"))
    ]
    public JournalId parmJournalNum( JournalId _journalNum = journalNum)
    {
        journalNum = _journalNum;
        return journalNum;
    }

    [
        //DataMemberAttribute(identifierStr(Postingdate)),
        DataMemberAttribute('Postingdate'),
        SysOperationLabelAttribute('Posting Date'),
        SysOperationDisplayOrderAttribute('2'),
        SysOperationHelpTextAttribute(literalStr("Posting Date"))
    ]
    public TransDate parmPostingDate(TransDate _postingDate = postingDate)
    {
        postingDate = _postingDate;
        return postingDate;
    }

    public boolean validate()
    {
        boolean isValid = true;
        if (!custAccount)
        {
            isValid = checkFailed(strFmt("@SYS84753", custAccount));
        }
        /*if (!filePath)
        {
            isValid = checkFailed(strFmt("@SYS84753", filePath));
        }*/
     
        return isValid;
    }

}
======================================================================
Controller:

class CITCustPaymImportController extends SysOperationServiceController
{
    Common  callerRecord; 
 
    void new()
    {
        super();

        this.parmClassName(classStr(CITCustPaymImportService));
        this.parmMethodName(methodStr(CITCustPaymImportService, process));
        this.parmDialogCaption('Customer payments Import');
    }

    public static void main(Args _args)
    {
        CITCustPaymImportController controller;
        controller = new CITCustPaymImportController();
     
        controller.parmShowDialog(true);
        CITCustPaymImportContract contract;
        contract    =   controller.getDataContractObject();
     
        if(_args.parm())
        {         
            contract.parmJournalNum(_args.parm());
        } 
        controller.startOperation();
    }

    public LabelType parmDialogCaption(LabelType _dialogCaption = "")
    {
        LabelType caption;
        caption = "Customer payments Import";
        return caption;
    }

    private void initFromCaller()
    {
     
        LedgerJournalTrans       ledgerJournalTrans;
     
    }

    public boolean canGoBatch()
     {
        return false;
     }

    public Common parmCallerRecord(Common _callerRecord = callerRecord)
    {
        callerRecord = _callerRecord;
        return callerRecord;
    }

    ///    Refreshes the calling form data source.
    protected void refreshCallerRecord()
    {
        FormDataSource callerDataSource;
        if (this.parmCallerRecord() && this.parmCallerRecord().dataSource())
        {
            callerDataSource = this.parmCallerRecord().dataSource();
            callerDataSource.research(true);
        }
     }

}

==================================================================
UI Builder :

class CITCustPaymImportUIBuilder extends SysOperationAutomaticUIBuilder
{
    Dialog      dlg;
    DialogField     dialogCustAcc;
    DialogField     dialogFilePath;
    DialogField     dialogPostingDate;
    DialogField     dialogJournalNum;
    str FileUploadName = 'FileUpload';
    private const str OkButtonName = 'Upload';
    str fileUrl;
    FileUploadBuild  dialogFileUpload;
    //dialogField     dialogFileUpload;


    CITCustPaymImportContract   contract;
    public void build()
    {
        DialogGroup dlgGrp;
        contract = this.dataContractObject();
     

        //get the current dialog
        dlg = this.dialog();

        dialogCustAcc = this.addDialogField(methodStr(CITCustPaymImportContract, parmCustAccount),contract);
        dialogCustAcc.value('');
        //dialogFilePath = this.addDialogField(methodStr(CITCustPaymImportContract, parmFilePath),contract);
        dialogPostingDate = this.addDialogField(methodStr(CITCustPaymImportContract, parmPostingDate),contract);
        dialogPostingDate.value(systemDateGet());
        dialogJournalNum = this.addDialogField(methodStr(CITCustPaymImportContract, parmJournalNum),contract);
        //make required modifications to the dialog
        dlgGrp = dlg.addGroup('File Upload');
        dlgGrp.columns(2);
     
        FormBuildControl formBuildControl = dlg.formBuildDesign().control(dlgGrp.name());
     
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), FileUploadName);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileNameLabel("@SYS308842");
        dialogFileUpload.resetUserSetting();
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.fileTypesAccepted('.xlsx');
    }

    public void dialogPostRun(DialogRunbase _dialog)
    {
        //super(_dialog);
        FileUpload fileUpload = this.getFormControl(_dialog, FileUploadName);
       // fileUpload.notifyUploadCompleted += eventhandler(dlg.uploadCompleted);
        //this.setDialogOkButtonEnabled(_dialog, false);
        FileUploadTemporaryStorageResult fileUploadResult = fileUpload.getFileUploadResult() as FileUploadTemporaryStorageResult;
        info(strfmt("-%1",fileUploadResult));
        if (fileUploadResult != null && fileUploadResult.getUploadStatus())
        {
            fileUrl = fileUploadResult.getDownloadUrl();
            info(strfmt("%1", fileUrl));
            contract.parmFilePath(fileUrl);
         
         
        }
    }

    protected FormControl getFormControl(DialogRunbase _dialog, str _controlName)
    {
        return _dialog.formRun().control(_dialog.formRun().controlId( _controlName));
    }

    private void setDialogOkButtonEnabled(DialogRunbase _dialog, boolean _isEnabled)
    {
        FormControl okButtonControl = this.getFormControl(_dialog, OkButtonName);

        if (okButtonControl)
        {
            okButtonControl.enabled(_isEnabled);
        }
    }

    public void run()
    {
     
        try
        {
            ttsbegin;
            FileUpload fileUploadControl = this.getFormControl(dlg, FileUploadName);
            FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult() as FileUploadTemporaryStorageResult;
            info(strfmt("-%1",fileUploadResult));
            if (fileUploadResult != null && fileUploadResult.getUploadStatus())
            {
                fileUrl = fileUploadResult.getDownloadUrl();
                info(strfmt("%1", fileUrl));
         
         
            }
            ttscommit;
        }
        catch (Exception::Deadlock)
        {
            retry;
        }
    }

    public void postBuild()
    {
        contract            =   this.dataContractObject();
        dialogCustAcc = this.bindInfo().getDialogField(
        this.dataContractObject(), methodStr(CITCustPaymImportContract, parmCustAccount));
        dialogFilePath = this.bindInfo().getDialogField(
        this.dataContractObject(), methodStr(CITCustPaymImportContract, parmFilePath));
        dialogPostingDate = this.bindInfo().getDialogField(
        this.dataContractObject(), methodStr(CITCustPaymImportContract, parmPostingDate));
        dialogJournalNum = this.bindInfo().getDialogField(
        this.dataContractObject(), methodStr(CITCustPaymImportContract, parmJournalNum));
     
    }

    private void custAccLookup(FormStringControl custAcclookup)
    {
        /*Query query = new Query();
        QueryBuildDataSource qbds_CustTable;
        QueryBuildRange         qbrBlocked;
        SysTableLookup sysTableLookup;
     
        // Create an instance of SysTableLookup with the current calling form control.
        sysTableLookup = SysTableLookup::newParameters(tableNum(CustTable), custAcclookup);
        // Add fields to be shown in the lookup form.
        sysTableLookup.addLookupfield(fieldNum(CustTable,AccountNum));
        //sysTableLookup.addLookupfield(fieldNum(CustTable,Name));
        sysTableLookup.addLookupMethod(tableMethodStr(CustTable,Name));
        qbds_CustTable = query.addDataSource(tableNum(CustTable));
        //this.query().dataSourceTable(tablenum(PurchTable)).addRange(fieldnum(PurchTable, PurchStatus)).value(strfmt('!%1,!%2',enum2str(PurchStatus::Canceled),enum2str(purchstatus::Invoiced)));
        //qbds_CustTable.addRange(fieldNum(CustTable, Blocked)).value(enum2str(CustVendorBlocked::All),enum2str(CustVendorBlocked::Payment));
        qbds_CustTable.addRange(fieldNum(CustTable, Blocked)).value(strfmt('!%1,!%2',enum2str(CustVendorBlocked::All),enum2str(CustVendorBlocked::Payment)));
        sysTableLookup.parmQuery(query);
        // Perform the lookup
        sysTableLookup.performFormLookup();*/
        CustTable::lookupCustomer(custAcclookup, curExt());
    }

    public void postRun()
    {
        super();

        //Register overrides for form control events
        dialogCustAcc.registerOverrideMethod(
        methodstr(FormStringControl, lookup),
        methodstr(CITCustPaymImportUIBuilder, custAccLookup),
        this);
    }

    /// <summary>
    ///
    /// </summary>
    public void getFromDialog()
    {
     
        FileUpload fileUploadControl = dlg.formRun().control(dlg.formRun().controlId(FileUploadName));
       
        FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult() as FileUploadTemporaryStorageResult;
        if (fileUploadResult != null && fileUploadResult.getUploadStatus())
        {
            fileUrl = fileUploadResult.getFileId();
        }
        contract.parmFilePath(fileUrl);
        super();
    }


}
========================================================================
Service :

class CITCustPaymImportService extends SysOperationServiceBase
{
    DMFExecutionId      executionId;
    DMFDefinitionGroup  definitionGroup;
    CustAccount     custAccount;
    FilePath        filePath,filepath1;
    JournalId       journalNum;
    TransDate       postingDate;
    Map                 uniqueKeyFieldListStagingMap,stagingTargetFieldListMap, autoGenStagingMap;
    Map                 entityPermissionMap;
    guid                scopeIdentifier;
    boolean             processComposite;
    Batch           currentBatch;
FileUpload             fileUpload;
map                           mapInv;
boolean             isMapEnd;
    public void process(CITCustPaymImportContract _contract)
    {
        filePath        = _contract.parmFilePath();
        custAccount     = _contract.parmCustAccount();
        journalNum      = _contract.parmJournalNum();
        postingDate     = _contract.parmPostingDate();
        try
        {
            This.processOperations(custAccount,filePath,journalNum,postingDate);
        }
        catch (Exception::Deadlock)
        {
            retry;
        }

        catch (Exception::UpdateConflict)
        {
            if (appl.ttsLevel() == 0)
            {
                /*   if (xSession::currentRetryCount() >= #RetryNum)
                {
                throw Exception::UpdateConflictNotRecovered;
                }
                else
                {
                retry;
                }*/
            }
                else
                {
                    throw Exception::UpdateConflict;
                }
        }

        catch (Exception::Error)
        {
            error(strFmt("Error occured"));
            retry;
        }
    }

    Void processOperations(CustAccount _custAccount,FilePath  _filePath,JournalId _journalNum,TransDate _postingDate)
    {
 
        This. fileToDMStaging ();
        This. ProcessStagingData(_custAccount,_journalNum,_postingDate);
        This. stagingToTarget();
    }

    //This method execution will import the data from file to staging table
    Void fileToDMStaging()
    {
     
        DMFDefinitionGroupExecution     groupExecution;
        DMFDefinitionGroupEntity    dMFDefinitionGroupEntity;
        definitionGroup = DMFDefinitionGroup::find(CustParameters::find().CITImportProject);
        executionId             = DMFUtil::generateExecutionId(CustParameters::find().CITImportProject);
        Description description = strFmt('Execution - %1 for Definition Group - %2', executionId, CustParameters::find().CITImportProject);
        DMFDefinitionGroupExecution::insertOrDisplay(definitionGroup, executionId, description, false);
        select entity from dMFDefinitionGroupEntity where dMFDefinitionGroupEntity.DefinitionGroup == definitionGroup.DefinitionGroupName;
        ttsbegin;
        groupExecution = DMFDefinitionGroupExecution::find(definitionGroup.DefinitionGroupName,dMFDefinitionGroupEntity.Entity,executionId,true);
        groupExecution.FilePath = /*"C4PCUATTF";*/filePath;
        groupExecution.FilePath = groupExecution.applyTransforms(groupExecution.FilePath);
     
        groupExecution.ExcelLookUp =
                        DMFDefinitionGroupEntity::insertExcelLookUpValue(
                        groupExecution.DefinitionGroup,
                        groupExecution.Entity,
                        groupExecution.FilePath,
                        groupExecution.Source);
        groupExecution.update();
        ttscommit;
        DMFStagingWriterContract        contract = new DMFStagingWriterContract();
        DMFQuickImportExport::doPGImport(definitionGroup.DefinitionGroupName ,executionId);//Need to create extension of class DMFQuickImportExport to pass File path and assign it to the contract variable
    }

    public NoYes parmError(NoYes  _errorStatus = NoYes::NO)
    {
        //  errorStatus = _errorStatus;

        return  NoYes::NO;
    }

    //This method execution will process the staging data for particular execution Id
    Void processStagingdata(CustAccount _custAccount,JournalId _journalId,TransDate _postingDate)
    {
        customerPaymentJournalLineStaging       customerPaymentJournalLineStaging;
        LedgerJournalTable                      ledgerjournaltable;
        JournalTableData                        journalTableData;
        ledgerjournaltable  =   LedgerJournalTable::find(journalNum,false);
        Voucher voucher;
     
        if(ledgerjournaltable)
        {
             
            voucher     =      JournalTableData::newTable(ledgerjournaltable).journalVoucherNum().getNew(true);
         
        }
     
        Update_recordSet customerPaymentJournalLineStaging
                setting DefaultDimensionsForAccountDisplayValue= _custAccount,
                AccountDisplayValue = _custAccount,
                JournalBatchNumber = _journalId,
                TransactionDate = _postingDate,
                Voucher = voucher,
                CurrencyCode = 'USD',
                DocumentNumber = customerPaymentJournalLineStaging.MarkedInvoice
                where customerPaymentJournalLineStaging.executionId == executionId;
        select customerPaymentJournalLineStaging
                where customerPaymentJournalLineStaging.executionId == executionId;

        if (!this.isInvoiceExists(customerPaymentJournalLineStaging.MarkedInvoice))
        {
            This.assignInvoiceFromPO();
        }

        /* Else
        {
        // This.sumInvoiceId();
        }*/
    }

        //Assign InvoiceId based on PO number provided in file
        Boolean isInvoiceExists(InvoiceId   _invoiceid)
        {
            boolean invexists;
            CustInvoiceJour custInvoiceJour;
            select RecId from custInvoiceJour
                where custInvoiceJour.InvoiceId ==  _invoiceid;
            if(custInvoiceJour)
                invexists   =   true;
            else
                invexists   =   false;
            return invexists;
        }

        Void assignInvoiceFromPO()
        {
            CustomerPaymentJournalLineStaging   customerPaymentJournalLineStaging;
            SalesTable                          SalesTable;
            Amount                              invoiceAmount;
            CustTransOpen                       CustTransOpen;
            CustInvoiceJour                     custInvoiceJour;
            CustTrans                           custTrans;
            CustomerPaymentJournalLineStaging   customerPaymentJournalLineStagingLoc,customerPaymentJournalLineStagingins;
         
            MapEnumerator                   mapEnum;

            While select sum(CreditAmount) from customerPaymentJournalLineStaging
                    group by markedInvoice
                    where customerPaymentJournalLineStaging.executionId == executionId
             
            {
                mapInv = new Map(Types::String, types::Real);
                select SalesTable
                    where salesTable.PurchOrderFormNum==customerPaymentJournalLineStaging.MarkedInvoice;

                if (SalesTable)
                While select custInvoiceJour where custInvoiceJour.SalesId == SalesTable.SalesId
        Join custTrans where custTrans.Invoice == custInvoiceJour.InvoiceId
                    && custTrans.AccountNum == custInvoiceJour.InvoiceAccount
                    && custTrans.TransDate == custInvoiceJour.InvoiceDate
                    && custTrans.Voucher == custInvoiceJour.LedgerVoucher
                join CustTransOpen where CustTransOpen.AccountNum == custTrans.AccountNum
                                    && CustTransOpen.RefRecId == custTrans.RecId
            {
                mapInv.insert(custInvoiceJour.InvoiceId,custTransOpen.amountMST);
            }
            mapEnum = new MapEnumerator(mapInv);
            isMapEnd = false;
            if(mapEnum.moveNext())
            while select forupdate customerPaymentJournalLineStagingLoc
                where customerPaymentJournalLineStagingloc.MarkedInvoice == customerPaymentJournalLineStaging.MarkedInvoice
                                && customerPaymentJournalLineStagingloc.executionId == executionId
                {
                    mapEnum = this.assignInvoice(customerPaymentJournalLineStagingloc,mapEnum);
                    if (isMapEnd)           
                        break;
                }
            }
        }

        MapEnumerator assignInvoice(customerPaymentJournalLineStaging customerPaymentJournalLineStagingLoc,MapEnumerator mapenum)
    {
        Amount invoiceAmount;
        customerPaymentJournalLineStaging   customerPaymentJournalLineStagingins;
        invoiceAmount = mapEnum.CurrentValue();
        if (invoiceAmount >= (customerPaymentJournalLineStagingLoc.CreditAmount + customerPaymentJournalLineStagingLoc.CITDiscountAmount))
        {
            ttsbegin;
            customerPaymentJournalLineStagingLoc.MarkedInvoice = mapEnum.CurrentKey();
            customerPaymentJournalLineStagingLoc.update();
            ttscommit;
            /*if (!mapenum.moveNext())
            {
                isMapEnd = true;
                return mapEnum;
            }*/
         
            if(customerPaymentJournalLineStagingloc.CreditAmount == invoiceAmount)
            {
                if (!mapenum.moveNext())
                {
                    isMapEnd = true;
                    return mapEnum;
                }
            }
         
            else
            {
                mapinv.insert(mapEnum.currentKey(),invoiceAmount-(customerPaymentJournalLineStagingloc.CreditAmount+customerPaymentJournalLineStagingLoc.CITDiscountAmount));
            }
        }
        else
        {
            invoiceAmount = (customerPaymentJournalLineStagingLoc.CreditAmount+customerPaymentJournalLineStagingLoc.CITDiscountAmount)-invoiceAmount;
            ttsbegin;
            customerPaymentJournalLineStagingLoc.selectForUpdate(true);
            customerPaymentJournalLineStagingLoc.MarkedInvoice = mapEnum.Currentkey();
            customerPaymentJournalLineStagingLoc.CreditAmount = mapEnum.CurrentValue()-customerPaymentJournalLineStagingLoc.CITDiscountAmount;
            customerPaymentJournalLineStagingLoc.update();
            ttscommit;
            customerPaymentJournalLineStagingins.data(customerPaymentJournalLineStagingloc);
            customerPaymentJournalLineStagingins.LineNumber += 0.01;
            customerPaymentJournalLineStagingins.CreditAmount =   invoiceAmount;
            customerPaymentJournalLineStagingins.RecId  =   0;
            customerPaymentJournalLineStagingins.CITDiscountAmount = 0;
            customerPaymentJournalLineStagingins.MarkedInvoice = '';
            customerPaymentJournalLineStagingins.insert();
            if (!mapenum.moveNext())
            {
                isMapEnd = true;
                return mapenum;
            }
            mapenum = this.assignInvoice(customerPaymentJournalLineStagingins,MapEnum);
        }
        return mapenum;
    }

        Void stagingToTarget()
        {
            DmfDefinitionGroupExecution dmfDefinitionGroupExecution;
            dmfDefinitionGroupExecution=dmfDefinitionGroupExecution::find(CustParameters::find().CITImportProject,'Customer payment journal line',executionId);
            if (dmfDefinitionGroupExecution.ExecutionId)
            {
                ttsbegin;
                DMFDefinitionGroupExecution defGroupExec;

                update_recordset defGroupExec
                setting IsSelected = NoYes::yes,
                    ExecuteTargetStep = NoYes::Yes
                where defGroupExec.ExecutionId == DMFDefinitionGroupExecution.ExecutionId;

                ttscommit;
            }

            DMFentitywriter  Dmfentitywriter = new DMFentitywriter();
            Dmfentitywriter.parmEntityTableName('CustomerPaymentJournalLineStaging');
            Dmfentitywriter.parmDMFExecution(DMFExecution::find(executionId));
            Dmfentitywriter.parmDMFDefinitionGroupExecution(dmfDefinitionGroupExecution);
            Dmfentitywriter.parmExecutionId(executionId);
            Dmfentitywriter.run();
         
        }

}


To get Batch button for sysoperation framework , we need to add before controller class
[SysOperationJournaledParametersAttribute(true)]