CUSTOMER
CHANGE APPROVALS IN DYNAMICS 365 FINANCE AND OPERATIONS
In certain scenarios, few organizations may
need approval process for changing the existing customer master data such as
Name, Bank account etc. D365 F&O has brought a new workflow approval
feature named as “Proposed customer change workflow” to
meet this requirement.
By inculcating this feature, the user can
configure the approval mechanism to have a hands on control on the updates to
the specified business critical customer master data fields. This feature
enables the change request to be approved before the changes get committed to
the customer master record.
PARAMETERS SETUP
Below are the parameters that are required to enable this
feature. Mark the Enable
customer approvals check box under Accounts receivable >
Setup > Accounts receivable parameters > General (Tab) > Customer
approval (Tab), as shown below.
Allocate the Data
entity behaviour value under Accounts receivable >
Setup > Account receivable parameters > General (Tab) > Customer
approval (Tab), from one of the 3 available lookup options, as appropriate, to
control the data import behaviour through data entities.
·
Allow
changes without approval - Customer record can be updated without approval.
- Reject changes – Changes
cannot be made to customer record.
- Create change proposals –
Changes
to the fields will be treated as proposed changes and subject to
required approvals.
Enable the check
box against each field that needs approval, under Accounts receivable > Setup > Account receivable parameters > General (Tab) > Customer approval
(Tab), as shown below. In this example, Test field is enabled to illustrate the process.
WORKFLOW CONFIGURATION
Configure a new workflow by selecting the workflow type
named Proposed
customer change workflow under Accounts
receivable > Setup > Accounts receivable workflows, as shown below
and setup the workflow as per business need.
UPDATE CUSTOMER DATA
Once the workflow is configured, try to update the Test for the existing customer from Accounts receivable > Customers > All
customers > Edit.
Change the Test
and observe that system will pop up a dialog by showing the current and
proposed Test, for your review. And
one can discard the changes if required.
Close the Proposed
change dialog and submit the change to workflow.
Approver can click on the proposed change button
on the customer master record, to view the proposed changes in the customer
data before taking an appropriate action.
If the workflow is approved by the approver, then the changed
data will get updated in Test field.
Once the workflow approval request is completed then the
system will update the Test in the customer master with the proposed field
value.
Add new field for Proposed
customer changes workflow
- Step1. Create extension for CustTableChangeProposalField
and an Enum. add
an element with name Test.
- Step2. Create post event handler or COC for
CustTableChangeProposalFieldEnablement/InitializeAll method and add this line
for your field
[ExtensionOf(tableStr(CustTableChangeProposalFieldEnablement))]
final class CustTableChangeProposalFieldEnablement _Extension
{
/// <summary>
/// Creates entries for all fields if they do not already
exist.
/// </summary>
public static void initializeAll()
{
next initializeAll();
CustTableChangeProposalFieldEnablement::findOrCreate(CustTableChangeProposalField::Test);
}
}
- Step 3. Create extension of CustTableChangeProposal table and add Test
field and an enum filed IsChangedTest.
- Step 4. Create cust change proposal form extension and add a new
group for Test. This will enable to see your changes to Test filed in the
proposal changes form from Customer form when workflow is activated
Step 5 . Create extension for CustChangePraposal form write the below
code in disableDiscardbutton() method and ShowHideGroups() method[ExtensionOf(formStr(custChangeProposal))]
final class CustTableChange_Extension
{
/// <summary>
/// Controls the visibility of groups representing the
individual grid rows
/// </summary>
public void showHideGroups()
{
next showHideGroups();
TestGroup.visible(CustTableChangeProposal.IsChangedTest);
}
/// <summary>
/// Disable all the DiscardTest button on the form
/// </summary>
protected void disableDiscardButtons()
{
next disableDiscardButtons();
DiscardTest.enabled(false);
}
}
- Step 6. Write the below code in Onclicked DiscardTestChange button
of form CustChangeProposal
/// <summary>
/// used to create new field and update the tabel
CustTableChangeProposal
/// </summary>
/// <param name="sender">DiscardTest</param>
/// <param name="e">Clicked</param>
[FormControlEventHandler(formControlStr(CustChangeProposal, DiscardTest),
FormControlEventType::Clicked)]
public static void DiscardTest_OnClicked(FormControl sender, FormControlEventArgs e)
{
CustTableChangeProposal CustTableChangeProposal = sender.formRun().dataSource(1).cursor();
ttsbegin;
CustTableChangeProposal localRecord = CustTableChangeProposal::findByCustRecId(CustTableChangeProposal.CustTable, true);
localRecord.IsChangedTest= NoYes::No;
localRecord.update();
ttscommit;
}
- Step 7 : Create extension for table
CustTableChangeProposal and extend methods like isRedundant() and
setFlagForChangedField()
[ExtensionOf(tableStr(CustTableChangeProposal))]
final class CustTableChangeProposal_Extension
{
/// <summary>
/// Sets the flag marking a change for a specific field.
/// </summary>
/// <param name = "_controlledField">CustTableChangeProposalField</param>
public void setFlagForChangedField(CustTableChangeProposalField
_controlledField)
{
next setFlagForChangedField(_controlledField);
switch (_controlledField)
{
case CustTableChangeProposalField::Test :
this.IsChangedTest = NoYes::Yes;
break;
}
}
/// <summary>
/// Checks if the record contains no
active changes, and is therefore redundant.
/// </summary>
/// <returns>True if the
record contains no changed field information;false otherwise.</returns>
public boolean isRedundant()
{
boolean ret = next isRedundant();
boolean Ischanged;
if (ret)
{
Ischanged = !(ret || this.IsChangedTest);
if(! Ischanged)//Do not delete the change
{
ret = false;
}
}
return ret;
}
}
and create event handler to update IsChangedTest
field
/// <summary>
/// Adjusts values to keep track of
changes and executes the update
/// </summary>
/// <param
name="args">CustTableChangeProposal</param>
[PostHandlerFor(tableStr(CustTableChangeProposal),tableMethodStr(CustTableChangeProposal, update))]
public static void CustTableChangeProposal_Post_update(XppPrePostArgs args)
{
CustTableChangeProposal changeProposal = args.getThis();
if (changeProposal.Test != changeProposal.orig().Test)
{
changeProposal.IsChangedTest = NoYes::Yes;
}
}
}
- Step 8: Create extension for CustTable form and place the below
code. Modified event on the Test would be captured and created as a change
proposal for workflow
/// <summary>
/// This method is used for modify the newly added test
control.
/// </summary>
/// <param name="sender">CustTable_Test</param>
/// <param
name="e">Modified</param>
[FormControlEventHandler(formControlStr(CustTable, CustTable_Test), FormControlEventType::Modified),SuppressBPWarning('BPParameterNotUsed', "Parameter e is required")]
public static void CustTable_Test_OnModified(FormControl sender, FormControlEventArgs e)
{
FormRun formRunCustTable =
sender.formRun() as FormRun;
FormDataSource CustTableFD=sender.dataSourceObject();
CustTable
custTableRecord=CustTableFD.cursor();
formRunCustTable.modifiedControlledField(
fieldNum(CustTable, Test),
fieldNum(CustTableChangeProposal, Test),
custTableRecord,
CustTableChangeProposalField::Test);
}
- Step 9: The last step would to update the currency filed in the
Customer table after the workflow, So create extension for
CustTableChangePraposalApply and write the below code
[ExtensionOf(classStr(CustTableChangeProposalApply))]
final class CusttableChangeProposalApply_Extension
{
/// <summary>
/// Sets values of <c>CustTable</c> fields
based on change proposal data.
/// </summary>
/// <param name =
"_custTableToUpdate">CustTable</param>
/// <param name =
"_dirPartyToUpdate">DirPartyTable</param>
protected void initializeCustTable(CustTable _custTableToUpdate, DirPartyTable _dirPartyToUpdate)
{
if(proposal.IsChangedTest)
{
_custTableToUpdate.Test = proposal.Test;
}
next initializeCustTable(_custTableToUpdate,_dirPartyToUpdate);
}
}
Keep Daxing !!