Created
June 16, 2022 18:31
-
-
Save anesvijskij/0f194da32b5a45e9f293437f9a6ad462 to your computer and use it in GitHub Desktop.
Draft for ARInvoiceEntry workflow customization in 2021R2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using PX.Common; | |
using PX.Data; | |
using PX.Data.WorkflowAPI; | |
using PX.Objects.AR; | |
namespace MyProject | |
{ | |
using static BoundedTo<ARInvoiceEntry, ARInvoice>; | |
/// <summary> | |
/// DAC extension with new | |
/// </summary> | |
public class ARInvoice_ReviewExtension : PXCacheExtension<ARInvoice> | |
{ | |
#region Events | |
public class Events : PXEntityEvent<ARInvoice>.Container<Events> | |
{ | |
public PXEntityEvent<ARInvoice> OnUpdateCuryOrigChanged; | |
} | |
#endregion | |
#region UsrReviewed | |
/// <summary> | |
/// Additional DAC field to store 'reviewed' mark | |
/// </summary> | |
public abstract class usrReviewed : PX.Data.BQL.BqlBool.Field<usrReviewed> | |
{ | |
} | |
[PXDBBool] | |
[PXDefault(false)] | |
[PXUIField(DisplayName = "Reviewed")] | |
public virtual Boolean? UsrReviewed { get; set; } | |
#endregion | |
// New status | |
#region PendingReview Status | |
public const string PendingReview = "I"; // 'R' is already used for CreditHold | |
public class pendingReview : PX.Data.BQL.BqlString.Constant<pendingReview> | |
{ | |
public pendingReview() : base(PendingReview) | |
{ | |
} | |
} | |
#endregion | |
} | |
/// <summary> | |
/// Class, that represent union of two DAC properties | |
/// Event will be fired if any of CuryOrigDocAmt OR CuryOrigDiscAmt fields will be changed | |
/// </summary> | |
public class OnUpdateCuryOrig : TypeArrayOf<IBqlField> | |
.FilledWith<ARInvoice.curyOrigDocAmt, ARInvoice.curyOrigDiscAmt> | |
{ | |
} | |
// ReSharper disable once InconsistentNaming | |
// ReSharper disable once UnusedMember.Global | |
public class ARInvoiceEntry_ReviewWorkflowExtension : PXGraphExtension<ARInvoiceEntry_Workflow, ARInvoiceEntry> | |
{ | |
protected void _(Events.FieldUpdated<ARInvoice, ARInvoice.curyOrigDocAmt> e) | |
{ | |
if (e.Row != null) | |
{ | |
ARInvoice_ReviewExtension.Events.Select(it => it.OnUpdateCuryOrigChanged) | |
.FireOn(this.Base, e.Row); | |
} | |
} | |
protected void _(Events.FieldUpdated<ARInvoice, ARInvoice.curyOrigDiscAmt> e) | |
{ | |
if (e.Row != null) | |
{ | |
ARInvoice_ReviewExtension.Events.Select(it => it.OnUpdateCuryOrigChanged) | |
.FireOn(this.Base, e.Row); | |
} | |
} | |
/// <summary> | |
/// Action to mark document as reviewed | |
/// </summary> | |
public PXAction<ARInvoice> MarkReviewed; | |
[PXButton] | |
[PXUIField(DisplayName = "Mark as Reviewed")] | |
public virtual void markReviewed() | |
{ | |
} | |
/// <summary> | |
/// Here we have additional condition, that will be used in workflow | |
/// </summary> | |
public class Conditions : Condition.Pack | |
{ | |
/// <summary> | |
/// UsrReviewed == True | |
/// </summary> | |
public Condition IsInspected => GetOrCreate(b => b.FromBql< | |
ARInvoice_ReviewExtension.usrReviewed.IsEqual<True>>()); | |
/// <summary> | |
/// UsrReviewed == False | |
/// </summary> | |
public Condition IsNotInspected => GetOrCreate(b => b.FromBql< | |
ARInvoice_ReviewExtension.usrReviewed.IsEqual<False>>()); | |
} | |
/// <summary> | |
/// Override default screen configuration | |
/// </summary> | |
/// <param name="config"></param> | |
public override void Configure(PXScreenConfiguration config) | |
{ | |
Configure(config.GetScreenConfigurationContext<ARInvoiceEntry, ARInvoice>()); | |
} | |
private void Configure(WorkflowContext<ARInvoiceEntry, ARInvoice> context) | |
{ | |
const string initialState = "_"; | |
// Get 'Process' category to add one more action below | |
var processingCategory = context.Categories.Get(ARInvoiceEntry_Workflow.CategoryID.Processing); | |
// Get conditions pack to use it workflow configuration | |
var conditions = context.Conditions.GetPack<Conditions>(); | |
// Include MarkReviewed action into screen configuration | |
var markReviewedAction = context.ActionDefinitions.CreateExisting<ARInvoiceEntry_ReviewWorkflowExtension>( | |
extension => extension.MarkReviewed, act => act | |
// add MarkReviewed into 'Process' category | |
.WithCategory(processingCategory) | |
// update usrReviewed field on MarkReviewed execution | |
.WithFieldAssignments(fields => | |
fields.Add<ARInvoice_ReviewExtension.usrReviewed>(v => | |
v.SetFromValue(true)))); | |
// Create new workflow event handler OnUpdateCuryOrigHandler, that will be subscribed on changing | |
// of DAC's CuryOrigDocAmt OR CuryOrigDiscAmt fields | |
var onUpdateCuryOrigHandler = context.WorkflowEventHandlers.Create(config => | |
config.WithTargetOf<ARInvoice>() | |
.OfEntityEvent<ARInvoice_ReviewExtension.Events>(events => events.OnUpdateCuryOrigChanged) | |
.IsNew("OnUpdateCuryOrigHandler") | |
.UsesTargetAsPrimaryEntity() | |
// when one of the amount fields changed - usrReviewed is returned back to FALSE | |
.WithFieldAssignments(fields => fields.Add<ARInvoice_ReviewExtension.usrReviewed>(v => | |
v.SetFromValue(false)))); | |
// Update Screen Configuration for ARInvoiceEntry | |
context.UpdateScreenConfigurationFor(screen => | |
// Update default ARInvoiceEntry workflow | |
screen.UpdateDefaultFlow(flow => | |
// modify workflow states | |
flow.WithFlowStates(states => | |
{ | |
states.Add<ARInvoice_ReviewExtension.pendingReview>(flowState => | |
{ | |
return flowState | |
.WithActions(actions => | |
{ | |
actions.Add(markReviewedAction, a => a.IsDuplicatedInToolbar()); | |
actions.Add(g => g.putOnHold); | |
}).WithEventHandlers(handlers => { handlers.Add(onUpdateCuryOrigHandler); }); | |
}); | |
}) | |
// modify transitions for the new state | |
.WithTransitions(transitions => | |
{ | |
#region Changes in transitions to reorder states | |
transitions.UpdateGroupFrom(initialState, ts => | |
{ | |
ts.Update( | |
t => t.To<ARDocStatus.pendingPrint>().IsTriggeredOn(g => g.initializeState) | |
.When(context.Conditions.Get("IsPendingPrint")), | |
transition => transition.PlaceAfter(source => | |
source.From(initialState).To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(g => g.initializeState))); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.hold>(ts => | |
{ | |
ts.Update( | |
t => t.To<ARDocStatus.pendingPrint>().IsTriggeredOn(g => g.releaseFromHold) | |
.When(context.Conditions.Get("IsPendingPrint")), | |
transition => transition.PlaceAfter(source => | |
source.From<ARDocStatus.hold>().To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(g => g.releaseFromHold))); | |
ts.Update( | |
t => t.To<ARDocStatus.pendingPrint>().IsTriggeredOn(g => g.OnUpdateStatus) | |
.When(context.Conditions.Get("IsPendingPrint")), | |
transition => transition.PlaceAfter(source => | |
source.From<ARDocStatus.hold>().To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(g => g.OnUpdateStatus))); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.creditHold>(ts => | |
{ | |
ts.Update( | |
t => t.To<ARDocStatus.pendingPrint>() | |
.IsTriggeredOn(g => g.releaseFromCreditHold) | |
.When(context.Conditions.Get("IsPendingPrint")), | |
transition => transition.PlaceAfter(source => | |
source.From<ARDocStatus.creditHold>().To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(g => g.releaseFromCreditHold))); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.balanced>(ts => | |
{ | |
ts.Update( | |
t => t.To<ARDocStatus.pendingPrint>().IsTriggeredOn(g => g.OnUpdateStatus) | |
.When(context.Conditions.Get("IsPendingPrint")), | |
transition => transition.PlaceAfter(source => | |
source.From<ARDocStatus.balanced>().To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(g => g.OnUpdateStatus))); | |
}); | |
#endregion | |
#region Changes in transitions only to add one state | |
transitions.UpdateGroupFrom(initialState, ts => | |
{ | |
ts.Add(t => t // New Pending Approval | |
.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.initializeState) | |
.When(conditions.IsNotInspected) | |
.PlaceAfter(selector => selector | |
.To<ARDocStatus.pendingPrint>().IsTriggeredOn(g => g.initializeState)) | |
); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.hold>(ts => | |
{ | |
ts.Add(t => t | |
.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.releaseFromHold) | |
.DoesNotPersist() | |
.When(conditions.IsNotInspected) | |
.PlaceAfter(selector => selector | |
.To<ARDocStatus.pendingPrint>().IsTriggeredOn(g => g.releaseFromHold)) | |
); | |
ts.Add(t => t | |
.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.OnUpdateStatus) | |
.When(conditions.IsNotInspected) | |
.PlaceAfter(selector => selector | |
.To<ARDocStatus.pendingPrint>().IsTriggeredOn(g => g.OnUpdateStatus)) | |
); | |
ts.Add(t => t | |
.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(onUpdateCuryOrigHandler) | |
.When(conditions.IsNotInspected) | |
); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.creditHold>(ts => | |
{ | |
ts.Add(t => t.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.releaseFromCreditHold) | |
.When(conditions.IsNotInspected).PlaceAfter(source => | |
source.To<ARDocStatus.pendingPrint>() | |
.IsTriggeredOn(g => g.releaseFromCreditHold))); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.pendingPrint>(ts => | |
{ | |
ts.Add(t => t.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.printInvoice) | |
.When(conditions.IsNotInspected).PlaceAfter(source => | |
source.To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(g => g.printInvoice))); | |
ts.Add(t => t.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.OnUpdateStatus) | |
.When(conditions.IsNotInspected).PlaceAfter(source => | |
source.To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(g => g.OnUpdateStatus))); | |
ts.Add(t => t | |
.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(onUpdateCuryOrigHandler) | |
.When(conditions.IsNotInspected) | |
); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.pendingEmail>(ts => | |
{ | |
ts.Add(t => t.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.OnUpdateStatus) | |
.When(conditions.IsNotInspected).PlaceAfter(source => | |
source.To<ARDocStatus.pendingPrint>() | |
.IsTriggeredOn(g => g.OnUpdateStatus))); | |
}); | |
transitions.AddGroupFrom<ARInvoice_ReviewExtension.pendingReview>(ts => | |
{ | |
ts.Add(t => t | |
.To<ARDocStatus.hold>() | |
.IsTriggeredOn(g => g.OnUpdateStatus) | |
.When(context.Conditions.Get("IsOnHold"))); | |
ts.Add(t => t | |
.To<ARDocStatus.creditHold>() | |
.IsTriggeredOn(markReviewedAction) | |
.When(context.Conditions.Get("IsOnCreditHold"))); | |
// ORDER IS IMPORTANT HERE! | |
ts.Add(t => t | |
.To<ARDocStatus.pendingEmail>() | |
.IsTriggeredOn(markReviewedAction) | |
.When(context.Conditions.Get("IsPendingEmail"))); | |
ts.Add(t => t | |
.To<ARDocStatus.pendingPrint>() | |
.IsTriggeredOn(markReviewedAction) | |
.When(context.Conditions.Get("IsPendingPrint"))); | |
ts.Add(t => t | |
.To<ARDocStatus.balanced>() | |
.IsTriggeredOn(markReviewedAction) | |
.When(context.Conditions.Get("IsBalanced"))); | |
ts.Add(t => t | |
.To<ARDocStatus.hold>() | |
.IsTriggeredOn(g => g.putOnHold) | |
.DoesNotPersist()); | |
ts.Add(t => t.To<ARDocStatus.scheduled>() | |
.IsTriggeredOn(g => g.OnConfirmSchedule) | |
.WithFieldAssignments(fas => | |
{ | |
fas.Add<ARInvoice.scheduled>(e => e.SetFromValue(true)); | |
fas.Add<ARInvoice.scheduleID>(e => e.SetFromExpression("@ScheduleID")); | |
})); | |
}); | |
transitions.UpdateGroupFrom<ARDocStatus.balanced>(ts => | |
{ | |
ts.Add(t => t.To<ARInvoice_ReviewExtension.pendingReview>() | |
.IsTriggeredOn(g => g.OnUpdateStatus) | |
.When(conditions.IsNotInspected).PlaceAfter(source => | |
source.To<ARDocStatus.pendingPrint>() | |
.IsTriggeredOn(g => g.OnUpdateStatus))); | |
}); | |
#endregion | |
})) | |
// add new action into configuration | |
.WithActions(actions => actions.Add(markReviewedAction)) | |
// modify fields in WorkflowConfiguration | |
.WithFieldStates(fields => | |
{ | |
// Add new 'PendingInspection' value to Status ComboBox | |
fields.Add<ARInvoice.status>(field => | |
field.SetComboValue(ARInvoice_ReviewExtension.PendingReview, "On Review")); | |
// Make new 'usrReviewed' field always disabled | |
fields.Add<ARInvoice_ReviewExtension.usrReviewed>(field => field.IsDisabledAlways()); | |
}) | |
// add new workflow event handler to the configuration | |
.WithHandlers(handlers => handlers.Add(onUpdateCuryOrigHandler))); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment