Sunday, July 3, 2016

Customize x++ workflow with Mulitple level of Approval in Ax 2012

// Customize x++ workflow with Mulitple level of Approval in Ax 2012
Table -
Create table
1) Approval Tracking
Code Method --> Sample to Get No Of approval for Current Project
Public static Counter getNoOfApproval(ProjId _projId, RefRecid _recid, Tableid _tableid, name _level)
{
    Counter i;
    Fcc_ProjApprovalTracking    approvalTracking;
    select count(RecId) from approvalTracking
        where approvalTracking.ProjId == _projId &&
              approvalTracking.RefRecId == _recid &&
              approvalTracking.RefTableId == _tableid &&
              approvalTracking.Level == _level;

    return any2int(approvalTracking.RecId);
}
Public static boolean approvalExist(ProjId _projid,
                                    Tableid _tableid,
                                    Refrecid _recid,
                                    Name _level,
                                    UserId _userid = curUserId())
{
     Boolean approvalExist;
    Fcc_ProjApprovalTracking    approvalTracking;

    select count(RecId) from approvalTracking
        where approvalTracking.ProjId == _projId &&
              approvalTracking.RefRecId == _recid &&
              approvalTracking.RefTableId == _tableid &&
              approvalTracking.Level == _level &&
              approvalTracking.UserName == _userid;
    if(approvalTracking.RecId >= 1)
        approvalExist = true;
    else
        approvalExist =false;
    return approvalExist;
}
2) Approval group with levels
Public static int GetLevels(Projid  _project)
{
    Fcc_ProjApprovalGroup   approvalGroup;
    int i;
    ;
    select  count(RecId)
        from approvalGroup where approvalGroup.ProjectId == _project
                && approvalGroup.Level like "L-*";
    i = any2int(approvalGroup.RecId);
    return i;
}
3) Approval user list with Levels
New Class to Get Mulitple level Approval and Passing to Next Level
Class --> (Refer Point Code - 1)
Class --> FOr Workflow Notification (Refer Point code - 8)
Form - Control
 1) Form --> Design --> Create New Group and Name
  Property - Auto decalration - yes
     Column Width and Column Height
             Color Scheme - RGB
            Back Style - Opaque
            Background Color - Yellow
 2) Form --> Design --> static Text
         property -  Auto decalration - yes
 3) Form-->Design--> Button (For Submit)
  Property - Auto decalration - yes
   Left - Right Edge
  Method - > Code (Refer Point Code - 2)
 4) Form-->Design--> Menu Button --> Two Button Conntrol (For Approve and Reject)
  Property - Auto decalration - yes
   Left - Right Edge
  Method -> Code (Refer Point Code - 3)
Form Method
 1) Init --> Code for Hiding Group Based on Requirement
 2) New Method --> ModifyCurrentLevelApproval (Refer Point Code - 4) (note : Only if required multiple level)
 3) New Method --> setApprovalCtrlVisibility (Refer Point Code - 5)
 4) Form -> parent Datasource -> Method-> Init-> Code (Refer Point Code - 6)
 5) Form -> parent Datasource -> Method-> Active -> Code (Refer Point Code - 7)
Code -->
Code 7 :
element.setApprovalCtrlVisibility(Fcc_ProjSOApproval::setVisibility(LedgerJournalTable_ds.cursor()));
Code 6 :
element.setApprovalCtrlVisibility(Fcc_ProjSOApproval::setVisibility(LedgerJournalTable));
Code 5 :
Public void setApprovalCtrlVisibility(container _con)
{
    // Group -
    // StaticText - StaticText
    // Button - Submit
    // Menubutton - Action ( approve and Reject)
    ProjApproval.visible(conPeek(_con,1));
    StaticText.text(conPeek(_con,2));
    Submit.visible(conPeek(_con,3));
    Action.visible(conPeek(_con,4));
}
Code 4:
public void ModifyCurrentLevelApproval(LedgerJournalTable _jourTable)
{
    Name LevelName;
    #define.Level1("L-0001") 
    #define.Level2("L-0002")
    #define.Level3("L-0003")
    #define.Level4("L-0004")
    #define.Level5("L-0005")
 // All ABove levels denoting Multiple level names
    switch(_jourTable.Fcc_currentLevel)
    {
        case 1 :
            LevelName = #Level1;
            break;
        case 2 :
            LevelName = #Level2;
            break;
        case 3 :
            LevelName = #Level3;
            break;
        case 4 :
            LevelName = #Level4;
            break;
        case 5 :
            LevelName = #Level5;
            break;
        default :
            break;
    }
    if (_jourTable.currentLevel && _jourTable.currentLevel != 0)
    {
        if( (Fcc_projApprovalTracking::getNoOfApproval(_jourTable.getProjid(),_jourTable.RecId,_jourTable.TableId,LevelName)) >=
                (Fcc_ProjApprovalGroup::GetMinApprover(_jourTable.getProjid(),LevelName)) )
        {
            if(Fcc_ProjApprovalGroup::GetLevels(_jourTable.getProjid()) == _jourTable.Fcc_currentLevel)
            {
                LedgerJournalTable.Fcc_currentLevel = 0;
            }
            else
            {
                LedgerJournalTable.Fcc_currentLevel = LedgerJournalTable.Fcc_currentLevel + 1;
            }
        }
    }
  /*  else if (_jourTable.Fcc_currentLevel == 0)
    {
         LedgerJournalTable.Fcc_currentLevel = 0;
    }*/
}
Code 3:
//Reject
void clicked()
{
    super();
    LedgerJournalTable.Fcc_ApprovalStatus = Fcc_ApprovalStatus::Rejected;
    Fcc_ProjApproval::changeStatus(LedgerJournalTable,Fcc_ApprovalStatus::Rejected);
    LedgerJournalTable_ds.research(true);
    LedgerJournalTable_ds.refresh();
}
//Approve
void clicked()
{
    Fcc_ProjApprovalGroup   approvalGroup;
    Fcc_ProjApprovalList    approvalList;
    Fcc_ProjApprovalTracking    approvalTracking;
    Fcc_ProjSOExeApprovalList   soExeList;
    Name     level;
    super();
    level = Fcc_ProjSOApproval::GetCurrentLevel(LedgerJournalTable);
    while select soExeList
        where soExeList.ProjectId == ProjTable::find(LedgerJournalTable.getProjid()).ParentId
    {
        Fcc_ProjSOWrkNotification::NotificationAlert(LedgerJournalTable
                                                    ,soExeList.ProjectId
                                                    ,level
                                                    ,soExeList.userId);
    }
    Fcc_ProjApproval::changeStatus(LedgerJournalTable,Fcc_ApprovalStatus::Approved);
    LedgerJournalTable_ds.research(true);
    LedgerJournalTable_ds.refresh();
}
Code 2:
void clicked()
{
    Name     level;
    Fcc_ProjSOExeApprovalList   soExeList;
    super();
    LedgerJournalTable.Fcc_ApprovalStatus = Fcc_ApprovalStatus::Submitted;
    level = Fcc_ProjSOApproval::GetCurrentLevel(LedgerJournalTable);
    while select soExeList
        where soExeList.ProjectId == ProjTable::find(LedgerJournalTable.getProjid()).ParentId
    {
        Fcc_ProjSOWrkNotification::NotificationAlert(LedgerJournalTable
                                                    ,soExeList.ProjectId
                                                    ,level
                                                    ,soExeList.userId);
    }
    Fcc_ProjApproval::changeStatus(LedgerJournalTable,Fcc_ApprovalStatus::Submitted);

    LedgerJournalTable_ds.research(true);
    LedgerJournalTable_ds.refresh();
}
Code 1:
class Fcc_ProjApproval
{
}
//Changet status and Updating current level
Public static void changeStatus(Common _common, Fcc_ApprovalStatus _status)
{
    Fcc_ProjApprovalTracking    apprTracking;
    Fcc_ProjSOApprovalGroup      apprgroupCmp;
    LedgerJournalTable  ledgerjournalTable,journalTableUpd;
    InventJournalTable  inventJournalTable,inventJourTableUpd;
    ProjId  projid;
    str level;

    switch(_common.TableId)
    {
        case tableNum(LedgerJournalTable):
            ledgerjournaltable = _common;
            projid = ProjTable::find(ledgerjournaltable.getProjid()).ParentId;
            apprTracking.RefTableId = _common.TableId;
            apprTracking.RefRecId = _common.RecId;
            apprTracking.Fcc_ApprovalStatus = _status;
            if (_status == Fcc_ApprovalStatus::Submitted)
            {
                apprTracking.Level = "";
            }
            else if (_status == Fcc_ApprovalStatus::Approved)
            {
                apprTracking.Level = Fcc_ProjSOApproval::GetCurrentLevel(_common);
            }
            apprgroupCmp.clear();
            select apprgroupCmp order by RecId desc
                        where apprgroupCmp.ProjectId == projid;
            if(apprgroupCmp.Level == apprTracking.Level)
            {
                ttsBegin;
                select forUpdate journalTableUpd
                    where journalTableUpd.JournalNum == ledgerjournaltable.JournalNum;
                if(journalTableUpd)
                {
                    journalTableUpd.Fcc_ApprovalStatus = Fcc_ApprovalStatus::Approved;
                    journalTableUpd.update();
                }
                ttsCommit;
            }
            apprTracking.ProjId = projid;
            apprTracking.UserName = curUserId();
            apprTracking.ApprovedRejectDate = systemDateGet();
            apprTracking.insert();
            break;
        case tableNum(InventJournalTable) :
            inventJournalTable = InventJournalTable::findByRecId(_common.recid,false);
            projid = inventJournalTable.getProjid();
            apprTracking.RefTableId = _common.TableId;
            apprTracking.RefRecId = _common.RecId;
            apprTracking.Fcc_ApprovalStatus = _status;
            if (_status == Fcc_ApprovalStatus::Submitted)
            {
                apprTracking.Level = "";
            }
            else if (_status == Fcc_ApprovalStatus::Approved)
            {
                apprTracking.Level = Fcc_ProjSOApproval::GetCurrentLevel(_common);
            }
            apprgroupCmp.clear();
            select apprgroupCmp order by RecId desc
                        where apprgroupCmp.ProjectId == projid;
            if(apprgroupCmp.Level == apprTracking.Level)
            {
                ttsBegin;
                select forUpdate inventJourTableUpd
                    where inventJourTableUpd.JournalId == inventJournalTable.JournalId;
                if(inventJourTableUpd)
                {
                    inventJourTableUpd.Fcc_ApprovalStatus = Fcc_ApprovalStatus::Approved;
                    inventJourTableUpd.update();
                }
                ttsCommit;
            }
            apprTracking.ProjId = projid;
            apprTracking.UserName = curUserId();
            apprTracking.ApprovedRejectDate = systemDateGet();
            apprTracking.insert();
            break;
        default :
            throw error("Must be called with Journal Table");
    }
}
//get levels
Public container getLevel(JournalId  _journalId)
{
    container                   conLevel;
    Fcc_ProjApprovalGroup       approvalGroup;
    Fcc_ProjApprovalList        approvalList;
    LedgerJournalTable          ledgerjournalTable;
    LedgerJournalTrans          ledgerjournalTrans, journalTransLevel;
    LedgerJournalTrans_Project  ledgerjournalTrans_Project, journalTrans_ProjectLevel;
    Name                        level;
    Counter                     i, totLevel, nextLevel;
    Fcc_ProjApprovalGroup       projApprovalGroup;
    Fcc_ProjApprovalList        projApprovalList;
    boolean                     executionApprovalExists;
        ;
    executionApprovalExists =false;
    ledgerjournalTable = LedgerJournalTable::find(_journalId);
    if(ledgerjournalTable.Fcc_currentLevel == 0 && ledgerjournalTable.Fcc_NextLevel == 0) // execution will happen if the journal is submitted for the first time
    {
        select journalTransLevel where journalTransLevel.JournalNum == ledgerjournalTable.JournalNum
            join journalTrans_ProjectLevel where journalTrans_ProjectLevel.RefRecId == journalTransLevel.RecId;
        // Check if Execution level exist
        select projApprovalGroup where projApprovalGroup.ProjectId == journalTrans_ProjectLevel.ProjId
                                    && projApprovalGroup.Level like "EX*";
        if(projApprovalGroup)
            executionApprovalExists = true;
        projApprovalGroup.clear();
        select count(RecId) from projApprovalGroup
            where projApprovalGroup.ProjectId == journalTrans_ProjectLevel.ProjId;
        totLevel = projApprovalGroup.RecId -1; // minus the Execution level
        select ledgerjournalTrans where ledgerjournalTrans.JournalNum == ledgerjournalTable.JournalNum
                join count(RecId) from ledgerjournalTrans_Project where ledgerjournalTrans_Project.RefRecId == ledgerjournalTrans.RecId
            && ledgerjournalTrans_Project.Fcc_ExecutionApproval == Fcc_ExecutionApproval::NeedsApproval;
        if(executionApprovalExists)
        {
            i++;
            if (ledgerjournalTrans_Project.recid >= 1 )
            {
                // Assume 10 as execution approval level
                conLevel = conIns(conLevel,i,10);
                i++;
                conLevel = conIns(conLevel,i,1);
            }
        }
        else
        {
            i++;
            if (totLevel > 1)
            {
                conLevel = conIns(conLevel,i,1);
                i++;
                conLevel = conIns(conLevel,i,2);
            }
        }
    }
    else
    {
        select journalTransLevel where journalTransLevel.JournalNum == ledgerjournalTable.JournalNum
            join journalTrans_ProjectLevel where journalTrans_ProjectLevel.RefRecId == journalTransLevel.RecId;
        // Check if Execution level exist
        select projApprovalGroup where projApprovalGroup.ProjectId == journalTrans_ProjectLevel.ProjId
                                    && projApprovalGroup.Level like "EX*";
        if(projApprovalGroup)
            executionApprovalExists = true;
        projApprovalGroup.clear();
        select count(RecId) from projApprovalGroup
            where projApprovalGroup.ProjectId == journalTrans_ProjectLevel.ProjId;
        totLevel = projApprovalGroup.RecId -1; // minus the Execution level
        if (ledgerjournalTable.Fcc_NextLevel <= totLevel)
        {
             i++;
            if (totLevel > 1)
            {
                conLevel = conIns(conLevel,i,ledgerjournalTable.Fcc_NextLevel);
                i++;
                conLevel = conIns(conLevel,i, totLevel - ledgerjournalTable.Fcc_NextLevel);
            }
        }
    }
    return conLevel;
}
//Check and validate action
Public boolean isActionEnabled(JournalId _journalId)
{
    Fcc_ProjApprovalGroup   approvalGroup;
    Fcc_ProjApprovalList    approvalList;
    LedgerJournalTable      ledgerjournalTable;
    LedgerJournalTrans      ledgerjournalTrans;
    LedgerJournalTrans_Project  ledgerjournalTrans_Project;
    Name        level;
    ledgerjournalTable = LedgerJournalTable::find(_journalId);
    select ledgerjournalTrans where ledgerjournalTrans.JournalNum == ledgerjournalTable.JournalNum
        join count(RecId) from ledgerjournalTrans_Project where ledgerjournalTrans_Project.RefRecId == ledgerjournalTrans.RecId
    && ledgerjournalTrans_Project.Fcc_ExecutionApproval == Fcc_ExecutionApproval::NeedsApproval;

    if (ledgerjournalTrans_Project.recid >= 1)
    {
    }
    select approvalGroup;
    return true;
   // select approvalGroup where approvalGroup.ProjectId
}
//Check appproval to submit workflow
Public static boolean chkApproval(JournalId _journalId)
{
    LedgerJournalTable  ledgerJournalTable;
    LedgerJournalTrans  ledgerJournalTrans;
    LedgerJournalTrans_Project  ledgerjournalTrans_Project;
    boolean canSubmit = false;
    select ledgerJournalTable
        where ledgerJournalTable.Fcc_ApprovalStatus == Fcc_ApprovalStatus::NotSubmitted
        && ledgerJournalTable.JournalNum == _journalId
    join ledgerJournalTrans
        where ledgerJournalTrans.JournalNum ==  ledgerJournalTable.JournalNum
    join count(RecId) from ledgerjournalTrans_Project
        where ledgerjournalTrans_Project.RefRecId == ledgerJournalTrans.RecId;
    if (ledgerjournalTrans_Project.RecId >= 1)
        canSubmit = true;
    else
        canSubmit = false;
    return canSubmit;
}
//Check Execution Approval - positng and final approval for Validating amount
Public static boolean chkExeApproval(JournalId _journalId)
{
    LedgerJournalTable  ledgerJournalTable;
    LedgerJournalTrans  ledgerJournalTrans;
    LedgerJournalTrans_Project  ledgerjournalTrans_Project;
    boolean canSubmit = false;
    select ledgerJournalTable
        where ledgerJournalTable.Fcc_ApprovalStatus == Fcc_ApprovalStatus::NotSubmitted
        && ledgerJournalTable.JournalNum == _journalId
    join ledgerJournalTrans
        where ledgerJournalTrans.JournalNum ==  ledgerJournalTable.JournalNum
    join count(RecId) from ledgerjournalTrans_Project
        where ledgerjournalTrans_Project.RefRecId == ledgerJournalTrans.RecId &&
            ledgerjournalTrans_Project.Fcc_ExecutionApproval == Fcc_ExecutionApproval::NeedsApproval;
    if (ledgerjournalTrans_Project.RecId >= 1)
        canSubmit = true;
    else
        canSubmit = false;
    return canSubmit;
}

Code 8:
class Fcc_ProjSOWrkNotification
{
}
//Alert sending
Public static Void AlertSend(Common _common,Name    _journalId,ProjId  _projId,Name    _level,UserId  _UserName)
{
    EventInbox inbox;
    LedgerJournalTable  ledgerjournalTable;
    InventJournalTable  inventJournalTable;
    ;
    inbox.initValue();
    inbox.ShowPopup = NoYes::Yes;
    switch(_common.TableId)
    {
        case tableNum(LedgerJournalTable):
            ledgerjournaltable = _common;
            inbox.AlertedFor = strfmt("Journal Number  %1 for %2 - %3 is waiting for next level of approval",_journalId,_projId,ledgerjournaltable.JournalName);
            inbox.AlertFieldId = fieldnum(ledgerjournaltable, JournalNum);
            inbox.Subject = "Project Expenses Journal Workflow Approval";
        case tableNum(InventJournalTable) :
            inventJournalTable = InventJournalTable::findByRecId(_common.recid,false);
            inbox.AlertedFor = strfmt("Journal Number is %1 for %2 - %3 is waiting for next level of approval",_journalId,_projId,inventJournalTable.JournalNameId);
            inbox.AlertFieldId = fieldnum(inventJournalTable, JournalId);
            inbox.Subject = "Project Item Journal Workflow Approval";
    }
    inbox.Message = strfmt("Journal Number  %1 - User %2",_journalId,_UserName);
    inbox.SendEmail = false;
    inbox.UserId = curuserid();
    inbox.TypeId = classnum(EventType);
    inbox.ParentTableId = _common.TableId;
    inbox.AlertTableId = _common.TableId;
    //inbox.TypeTrigger = EventTypeTrigger::FieldChanged;
    inbox.CompanyId = curext();
    inbox.InboxId = EventInbox::nextEventId();
    inbox.AlertCreatedDateTime = DateTimeUtil::getSystemDateTime();
    inbox.insert();
}
//Notification
Public static void NotificationAlert(Common _common,ProjId  _projId,Name    _level,UserId     _UserName)
{
    LedgerJournalTable  ledgerjournalTable;
    InventJournalTable  inventJournalTable;
    ;
    switch(_common.TableId)
    {
        case tableNum(LedgerJournalTable):
            ledgerjournaltable = _common;
            Fcc_ProjSOWrkNotification::AlertSend(_common,ledgerjournaltable.JournalNum,_projId,_level,_UserName);
            break;
        case tableNum(InventJournalTable) :
            inventJournalTable = InventJournalTable::findByRecId(_common.recid,false);
            Fcc_ProjSOWrkNotification::AlertSend(_common,inventJournalTable.JournalId,_projId,_level,_UserName);
            break;
        default :
            throw error("Must be called with Journal Table");
    }
}


No comments:

Post a Comment

Convert Call stack to readable format in D365FO X++

//Input --container _xppCallStack = xSession::xppCallStack();  Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFr...