如何通过自动化步骤在 Acumatica 中使用分配和批准图?
How to work with Assignment and Approval Maps in Acumatica via Automation Steps?
我需要制作使用分配和批准图。在 EP205000 页构建的地图使用模板是什么?我在 Acumatica 的文件 coderepository.xml 中进行了研究,并在那里找到了 EPApprovalAutomation class。我想使用它,但它需要在参数中使用实现 IAssignedMap 接口的 class 。它给出了另一个问题,因为 IAssignedMap 接口是内部的,这给出了另一个谜,如何使用 IAssignedMap 接口?什么是备选方案?
这个答案可能来得有点晚,但我相信它对其他人有用,所以我会分享它。
数据库的新 table 和字段
XXSetupApproval
为您的模块中的审批设置添加新设置 table(进一步的 XXSetupApproval)。您可以在下面看到所有必填字段,但如果您想要为不同类型的实体拆分批准,您可能需要添加任何其他参数。
CREATE TABLE XXSetupApproval
(
CompanyID int NOT NULL,
ApprovalID int NOT NULL identity,
AssignmentMapID int NOT NULL,
AssignmentNotificationID int NULL,
CreatedByID uniqueidentifier NOT NULL,
CreatedByScreenID char(8) NOT NULL,
CreatedDateTime datetime NOT NULL,
LastModifiedByID uniqueidentifier NOT NULL,
LastModifiedByScreenID char(8) NOT NULL,
LastModifiedDateTime datetime NOT NULL,
Tstamp timestamp NULL,
IsActive bit NOT NULL
)
GO
ALTER TABLE XXSetupApproval
ADD CONSTRAINT XXSetupApproval_PK PRIMARY KEY CLUSTERED (CompanyID, ApprovalID)
GO
XX注册
修改table您需要实施审批机制的实体(进一步XXRegister)。您的实体应包含三个必填字段,如下所示。
OwnerID uniqueidentifier NULL,
WorkGroupID int NULL,
Approved bit NOT NULL
XX设置
修改 table 模块中的主要设置(进一步的 XXSetup)。您的设置应包含一个必填字段,如下所示。根据您的实体名称命名此标志,因为它将指示是否启用批准机制(进一步的 XXRequestApproval)。
XXRequestApproval bit NULL
数据库的新更新脚本
更新 XXRegister table 并根据您的条件将所有现有记录的 Approved 标志设置为 1。用你自己的表达方式代替三个点。
EXEC sp_executesql N'UPDATE XXRegister SET Approved = 1 WHERE ...'
代码的新 table 和字段
AssignmentMapTypeXX
将您的实体添加到 AssignmentMapType class(进一步的 AssignmentMapTypeXX)。此类型应仅用于 select 所需类型的分配映射。
public static class AssignmentMapType
{
...
public class AssignmentMapTypeXX : Constant<string>
{
public AssignmentMapTypeXX() : base(typeof(XXRegister).FullName) { }
}
...
}
XX设置
根据数据库中的新字段向 XXSetup DAC 添加新属性和 classes。如果需要,使用任何其他属性。
#region XXRequestApproval
public abstract class xXRequestApproval : PX.Data.IBqlField { }
[EPRequireApproval]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Null)]
[PXUIField(DisplayName = "Require Approval")]
public virtual bool? XXRequestApproval { get; set; }
#endregion
XXSetupApproval
根据数据库中的 XXSetupApproval table 将新的 DAC 添加到代码中。 XXSetupApproval DAC 应实现 IAssignedMap 接口(AssignmentMapID、AssignmentNotificationID、IsActive 字段)。如果需要,使用任何其他属性。
[Serializable]
public partial class XXSetupApproval : IBqlTable, IAssignedMap
{
#region ApprovalID
public abstract class approvalID : IBqlField { }
[PXDBIdentity(IsKey = true)]
public virtual int? ApprovalID { get; set; }
#endregion
#region AssignmentMapID
public abstract class assignmentMapID : IBqlField { }
[PXDefault]
[PXDBInt]
[PXSelector(typeof(Search<EPAssignmentMap.assignmentMapID, Where<EPAssignmentMap.entityType, Equal<AssignmentMapType.AssignmentMapTypeXX>>>),
DescriptionField = typeof(EPAssignmentMap.name))]
[PXUIField(DisplayName = "Approval Map")]
public virtual int? AssignmentMapID { get; set; }
#endregion
#region AssignmentNotificationID
public abstract class assignmentNotificationID : IBqlField { }
[PXDBInt]
[PXSelector(typeof(PX.SM.Notification.notificationID), SubstituteKey = typeof(PX.SM.Notification.name))]
[PXUIField(DisplayName = "Pending Approval Notification")]
public virtual int? AssignmentNotificationID { get; set; }
#endregion
#region tstamp
public abstract class Tstamp : IBqlField { }
[PXDBTimestamp()]
public virtual byte[] tstamp { get; set; }
#endregion
#region CreatedByID
public abstract class createdByID : IBqlField { }
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
#endregion
#region CreatedByScreenID
public abstract class createdByScreenID : IBqlField { }
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
#endregion
#region CreatedDateTime
public abstract class createdDateTime : IBqlField { }
[PXDBCreatedDateTime()]
public virtual DateTime? CreatedDateTime { get; set; }
#endregion
#region LastModifiedByID
public abstract class lastModifiedByID : IBqlField { }
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
#endregion
#region LastModifiedByScreenID
public abstract class lastModifiedByScreenID : IBqlField { }
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
#endregion
#region LastModifiedDateTime
public abstract class lastModifiedDateTime : IBqlField { }
[PXDBLastModifiedDateTime()]
public virtual DateTime? LastModifiedDateTime { get; set; }
#endregion
#region IsActive
public abstract class isActive : IBqlField { }
[PXDBBool()]
[PXDefault(typeof(Search<XXSetup.xXRequestApproval>), PersistingCheck = PXPersistingCheck.Nothing)]
public virtual bool? IsActive { get; set; }
#endregion
}
XX注册
将 PXEmailSource 属性添加到 XXRegister DAC,这是 "Assignment and Approvals Maps" 树 select 或
所必需的
[PXEMailSource]
public partial class XXRegister : IBqlTable, EP.IAssign ...
根据数据库中的新字段向 XXRegister DAC 添加新属性和 classes。 XXRegister DAC 应实现 IAssign 接口(OwnerID、WorkgroupID 字段)。如果需要,使用任何其他属性。用你自己的表达方式代替三个点。
#region OwnerID
public abstract class ownerID : IBqlField { }
[PXDBGuid()]
[PXDefault(typeof(...), PersistingCheck = PXPersistingCheck.Nothing)]
[PX.TM.PXOwnerSelector()]
[PXUIField(DisplayName = "Owner")]
public virtual Guid? OwnerID { get; set; }
#endregion
#region WorkgroupID
public abstract class workgroupID : IBqlField { }
[PXDBInt]
[PXDefault(typeof(...), PersistingCheck = PXPersistingCheck.Nothing)]
[PX.TM.PXCompanyTreeSelector]
[PXUIField(DisplayName = "Workgroup", Enabled = false)]
public virtual int? WorkgroupID { get; set; }
#endregion
#region Approved
public abstract class approved : IBqlField { }
[PXDBBool]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Approved", Visibility = PXUIVisibility.Visible, Enabled = false)]
public virtual bool? Approved { get; set; }
#endregion
#region Rejected
public abstract class rejected : IBqlField { }
[PXBool]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
public bool? Rejected { get; set; }
#endregion
状态
为实体添加新的批准状态并在列表中使用它们。如果“P”和“R”已在使用,请使用其他字母。
public const string PendingApproval = "P";
public const string Rejected = "R";
public class ListAttribute : PXStringListAttribute
{
public ListAttribute() : base(
new string[] { ..., PendingApproval, Rejected, ... },
new string[] { ..., EP.Messages.PendingApproval, EP.Messages.Rejected, ... }) { ; }
}
实体图的新代码
在使用您的实体进行操作的图表中实施 EPApprovalAutomation 助手。使用您自己的参数而不是三个点。
public EPApprovalAutomation<...> Approval;
为 XXSetupApproval DAC 添加视图。用你自己的表达方式代替三个点。
public PXSelect<XXSetupApproval, Where<...>> SetupApproval;
主要设置图表的新代码
为 XXSetupApproval DAC 添加视图。
public PXSelect<APSetupApproval> SetupApproval;
根据 XXRequestApproval 字段的新值更新每个 XXSetupApproval 行。
protected virtual void XXSetup_XXRequestApproval_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
{
PXCache cache = this.Caches[typeof(XXSetupApproval)];
foreach (XXSetupApproval setup in PXSelect<XXSetupApproval>.Select(this))
{
setup.IsActive = (bool?)e.NewValue;
cache.Update(setup);
}
}
网页的新 table 和字段
XXSetup.aspx
将带有批准设置的新选项卡添加到设置的主页(XXSetup.aspx 进一步)。如果需要,使用任何其他参数。
<px:PXTabItem Text="Approval">
<Template>
<px:PXPanel ID="panelApproval" runat="server" >
<px:PXLayoutRule runat="server" LabelsWidth="S" ControlSize="XM" />
<px:PXCheckBox ID="chkXXRequestApproval" runat="server" AlignLeft="True" Checked="True" DataField="XXRequestApproval" CommitChanges="True" />
</px:PXPanel>
<px:PXGrid ID="gridApproval" runat="server" DataSourceID="ds" SkinID="Details" Width="100%" >
<AutoSize Enabled="True" />
<Levels>
<px:PXGridLevel DataMember="SetupApproval" >
<RowTemplate>
<px:PXLayoutRule runat="server" StartColumn="True" LabelsWidth="M" ControlSize="XM" />
<px:PXSelector ID="edAssignmentMapID" runat="server" DataField="AssignmentMapID" AllowEdit="True" CommitChanges="True" />
<px:PXSelector ID="edAssignmentNotificationID" runat="server" DataField="AssignmentNotificationID" AllowEdit="True" />
</RowTemplate>
<Columns>
<px:PXGridColumn DataField="AssignmentMapID" Width="250px" RenderEditorText="True" TextField="AssignmentMapID_EPAssignmentMap_Name" />
<px:PXGridColumn DataField="AssignmentNotificationID" Width="250px" RenderEditorText="True" />
</Columns>
</px:PXGridLevel>
</Levels>
</px:PXGrid>
</Template>
</px:PXTabItem>
XXRegister.aspx
将新字段“已批准”添加到实体的主页(进一步XXRegister.aspx)。如果需要,使用任何其他参数。
<px:PXCheckBox ID="chkApproved" runat="server" DataField="Approved" CommitChanges="True" Enabled="False" />
向 XXRegister.aspx 网页添加带有批准信息的新选项卡。如果需要,使用任何其他参数。
<px:PXTabItem Text="Approval Details" BindingContext="form" RepaintOnDemand="false">
<Template>
<px:PXGrid ID="gridApproval" runat="server" DataSourceID="ds" Width="100%" SkinID="DetailsInTab" NoteIndicator="True" Style="left: 0px; top: 0px;">
<AutoSize Enabled="True" />
<Mode AllowAddNew="False" AllowDelete="False" AllowUpdate="False" />
<Levels>
<px:PXGridLevel DataMember="Approval">
<Columns>
<px:PXGridColumn DataField="ApproverEmployee__AcctCD" Width="160px" />
<px:PXGridColumn DataField="ApproverEmployee__AcctName" Width="160px" />
<px:PXGridColumn DataField="ApprovedByEmployee__AcctCD" Width="100px" />
<px:PXGridColumn DataField="ApprovedByEmployee__AcctName" Width="160px" />
<px:PXGridColumn DataField="ApproveDate" Width="90px" />
<px:PXGridColumn DataField="Status" AllowNull="False" AllowUpdate="False" RenderEditorText="True"/>
<px:PXGridColumn DataField="WorkgroupID" Width="150px" />
</Columns>
</px:PXGridLevel>
</Levels>
</px:PXGrid>
</Template>
</px:PXTabItem>
自动化定义的新自动化步骤
这是批准实施过程中最困难的部分,因为应该在实体的当前行为范围内创建一些新的自动化步骤。例如,实体具有相应的下一个状态和自动化步骤:"Hold" -> "Open"。我们应该在这两个步骤之间实施审批机制。然后应该创建三个新的自动化步骤:"Hold-Open"(如果我们不需要批准文档),"Hold-Pending Approval"(如果我们需要批准文档),"Pending Approval"(从该实体应该被批准或拒绝)。新的生命周期将如下所示:"Hold" -> "Hold-Open" OR "Hold-Pending Approval" -> "Open" OR "Pending Approval"。所以 "Hold-Open" 和 "Hold-Pending Approval" 自动化步骤只是开关,决定在 "Hold" 之后应该使用哪个自动化步骤。
<Step StepID="Hold-Open" Description="Hold-Open" GraphName="…" ViewName="Document" TimeStampName="tstamp">
<Filter FieldName="Status" Condition="Equals" Value="H" Operator="And" />
<Filter FieldName="Hold" Condition="Equals" Value="False" Value2="False" Operator="And" />
<Filter FieldName="Approved" Condition="Equals" Value="True" Value2="False" Operator="And" />
<Action ActionName="*" IsDefault="1">
<Fill FieldName="Status" Value="N" />
</Action>
</Step>
<Step StepID="Hold-Pending Approval" Description="Hold-Pending Approval" GraphName="…" ViewName="Document" TimeStampName="tstamp">
<Filter OpenBrackets="1" FieldName="Status" Condition="Equals" Value="H" Operator="Or" />
<Filter FieldName="Status" Condition="Equals" Value="N" CloseBrackets="1" Operator="And" />
<Filter FieldName="Hold" Condition="Equals" Value="False" Value2="False" Operator="And" />
<Filter FieldName="Approved" Condition="Equals" Value="False" Value2="False" Operator="And" />
<Action ActionName="*" IsDefault="1">
<Fill FieldName="Status" Value="P" />
</Action>
</Step>
感谢 Acumatica 开发团队的 Evgeny Kralko 所做的工作。
将此添加为答案,因为它对于评论来说太大了。我下面的回复基于 Gabriel 的回答...
我能够获得 Gabriel 发布的使用以下添加的步骤:(参考图 SOOrderEntry 以获取示例)
- 为您创建分配和批准映射记录
screen/entity
- 需要在您的 XXSetupApproval table 中记录链接
到上面创建的批准图 ID
- 因为IAssignedMap是内部的,你需要自己创建
继承 EPApprovalAutomation 的 XXApprovalAutomation class
并覆盖 GetAssignedMaps。在您的图表上使用它代替
EP批准自动化。确保在 XXSetupApproval SetupApproval 视图之后添加它,否则您将在页面上收到类似于 "The view with type 'XXSetupApproval' must be declared inside the graph for using EPApprovalAutomation".
的错误
- 将 PXActions 添加到 "Actions" 和 "Hold" 的图形中。如果您没有执行此操作,则在尝试批准时可能会收到以下错误消息:"Automation
screen/graph %GraphName% 存在但配置不正确。
找不到操作 - 'Action'"
- 为 "Approve" 或 "Reject" 菜单项添加另一个自动化步骤
操作下拉菜单。我遵循了标准销售订单“SO Pending
批准”自动化步骤作为创建自定义图形的基础
审批流程自动化步骤。
如果您想填写 EPApproval 字段,例如批准人在批准表格上看到的描述,您可以在包含批准设置的图表中附加一个缓存,如下所示:
[PXDBString(60, IsUnicode = true)]
[PXDefault(typeof(MyDac.description), PersistingCheck = PXPersistingCheck.Nothing)]
protected virtual void EPApproval_Descr_CacheAttached(PXCache 发送方)
{
}
如果您希望批准屏幕上的 "Type" 值是用户友好的,而不是对象命名空间 (PX.Objects.MyStuff.MyDac),则在主 DAC 上使用 PXCacheName 属性,例如所以:
[PXEMailSource]
[可序列化]
[PXCacheName("My DAC")]
[PXPrimaryGraph(typeof(MyGraph))]
public class MyDac : PX.Data.IBqlTable, PX.Data.EP.IAssign
{...}
我的自定义图表上的自定义审批流程功能齐全。大 help/thanks 感谢 Gabriel 和 Evgeny 的这篇文章。我使用的 Acumatica 版本是 5.30.2233。一个限制是无法打包自动化步骤,因此从自定义包分发它不灵活。
如果您检查 RQRequestEntry,"Hold"
中还有一个附加代码
if (order.Hold != true && order.Approved != true)
{
order.CheckBudget = false;
if (order.BudgetValidation == true)
foreach (RQBudget budget in this.Budget.Select())
{
if (budget.RequestAmt > budget.BudgetAmt)
{
order.CheckBudget = true; break;
}
}
if(order.CheckBudget == true)
{
RQRequestClass cls = this.reqclass.SelectWindowed(0,1,order.ReqClassID);
if (cls != null && cls.BudgetValidation == RQRequestClassBudget.Error)
throw new PXRowPersistedException(typeof(RQRequest).Name, order, Messages.CheckBudgetWarning);
}
if (Setup.Current.RequestAssignmentMapID != null)
{
var processor = new EPAssignmentProcessor<RQRequest>();
processor.Assign(order, Setup.Current.RequestAssignmentMapID);
order.WorkgroupID = order.ApprovalWorkgroupID;
order.OwnerID = order.ApprovalOwnerID;
}
}
yield return (RQRequest)Document.Search<RQRequest.orderNbr>(order.OrderNbr);
我一直在摸索第三级审批步骤,说明书上没有这部分。我什至尝试调试 acumatica 的代码,那里似乎没有错误。为了其他开发者的利益,这里是您所需要的
您需要将这部分代码分配给下一个审批人:
if (Setup.Current.RequestAssignmentMapID != null)
{
var processor = new EPAssignmentProcessor<RQRequest>();
processor.Assign(order, Setup.Current.RequestAssignmentMapID);
order.WorkgroupID = order.ApprovalWorkgroupID;
order.OwnerID = order.ApprovalOwnerID;
}
我需要制作使用分配和批准图。在 EP205000 页构建的地图使用模板是什么?我在 Acumatica 的文件 coderepository.xml 中进行了研究,并在那里找到了 EPApprovalAutomation class。我想使用它,但它需要在参数中使用实现 IAssignedMap 接口的 class 。它给出了另一个问题,因为 IAssignedMap 接口是内部的,这给出了另一个谜,如何使用 IAssignedMap 接口?什么是备选方案?
这个答案可能来得有点晚,但我相信它对其他人有用,所以我会分享它。
数据库的新 table 和字段
XXSetupApproval
为您的模块中的审批设置添加新设置 table(进一步的 XXSetupApproval)。您可以在下面看到所有必填字段,但如果您想要为不同类型的实体拆分批准,您可能需要添加任何其他参数。
CREATE TABLE XXSetupApproval
(
CompanyID int NOT NULL,
ApprovalID int NOT NULL identity,
AssignmentMapID int NOT NULL,
AssignmentNotificationID int NULL,
CreatedByID uniqueidentifier NOT NULL,
CreatedByScreenID char(8) NOT NULL,
CreatedDateTime datetime NOT NULL,
LastModifiedByID uniqueidentifier NOT NULL,
LastModifiedByScreenID char(8) NOT NULL,
LastModifiedDateTime datetime NOT NULL,
Tstamp timestamp NULL,
IsActive bit NOT NULL
)
GO
ALTER TABLE XXSetupApproval
ADD CONSTRAINT XXSetupApproval_PK PRIMARY KEY CLUSTERED (CompanyID, ApprovalID)
GO
XX注册
修改table您需要实施审批机制的实体(进一步XXRegister)。您的实体应包含三个必填字段,如下所示。
OwnerID uniqueidentifier NULL,
WorkGroupID int NULL,
Approved bit NOT NULL
XX设置
修改 table 模块中的主要设置(进一步的 XXSetup)。您的设置应包含一个必填字段,如下所示。根据您的实体名称命名此标志,因为它将指示是否启用批准机制(进一步的 XXRequestApproval)。
XXRequestApproval bit NULL
数据库的新更新脚本
更新 XXRegister table 并根据您的条件将所有现有记录的 Approved 标志设置为 1。用你自己的表达方式代替三个点。
EXEC sp_executesql N'UPDATE XXRegister SET Approved = 1 WHERE ...'
代码的新 table 和字段
AssignmentMapTypeXX
将您的实体添加到 AssignmentMapType class(进一步的 AssignmentMapTypeXX)。此类型应仅用于 select 所需类型的分配映射。
public static class AssignmentMapType
{
...
public class AssignmentMapTypeXX : Constant<string>
{
public AssignmentMapTypeXX() : base(typeof(XXRegister).FullName) { }
}
...
}
XX设置
根据数据库中的新字段向 XXSetup DAC 添加新属性和 classes。如果需要,使用任何其他属性。
#region XXRequestApproval
public abstract class xXRequestApproval : PX.Data.IBqlField { }
[EPRequireApproval]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Null)]
[PXUIField(DisplayName = "Require Approval")]
public virtual bool? XXRequestApproval { get; set; }
#endregion
XXSetupApproval
根据数据库中的 XXSetupApproval table 将新的 DAC 添加到代码中。 XXSetupApproval DAC 应实现 IAssignedMap 接口(AssignmentMapID、AssignmentNotificationID、IsActive 字段)。如果需要,使用任何其他属性。
[Serializable]
public partial class XXSetupApproval : IBqlTable, IAssignedMap
{
#region ApprovalID
public abstract class approvalID : IBqlField { }
[PXDBIdentity(IsKey = true)]
public virtual int? ApprovalID { get; set; }
#endregion
#region AssignmentMapID
public abstract class assignmentMapID : IBqlField { }
[PXDefault]
[PXDBInt]
[PXSelector(typeof(Search<EPAssignmentMap.assignmentMapID, Where<EPAssignmentMap.entityType, Equal<AssignmentMapType.AssignmentMapTypeXX>>>),
DescriptionField = typeof(EPAssignmentMap.name))]
[PXUIField(DisplayName = "Approval Map")]
public virtual int? AssignmentMapID { get; set; }
#endregion
#region AssignmentNotificationID
public abstract class assignmentNotificationID : IBqlField { }
[PXDBInt]
[PXSelector(typeof(PX.SM.Notification.notificationID), SubstituteKey = typeof(PX.SM.Notification.name))]
[PXUIField(DisplayName = "Pending Approval Notification")]
public virtual int? AssignmentNotificationID { get; set; }
#endregion
#region tstamp
public abstract class Tstamp : IBqlField { }
[PXDBTimestamp()]
public virtual byte[] tstamp { get; set; }
#endregion
#region CreatedByID
public abstract class createdByID : IBqlField { }
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
#endregion
#region CreatedByScreenID
public abstract class createdByScreenID : IBqlField { }
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
#endregion
#region CreatedDateTime
public abstract class createdDateTime : IBqlField { }
[PXDBCreatedDateTime()]
public virtual DateTime? CreatedDateTime { get; set; }
#endregion
#region LastModifiedByID
public abstract class lastModifiedByID : IBqlField { }
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
#endregion
#region LastModifiedByScreenID
public abstract class lastModifiedByScreenID : IBqlField { }
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
#endregion
#region LastModifiedDateTime
public abstract class lastModifiedDateTime : IBqlField { }
[PXDBLastModifiedDateTime()]
public virtual DateTime? LastModifiedDateTime { get; set; }
#endregion
#region IsActive
public abstract class isActive : IBqlField { }
[PXDBBool()]
[PXDefault(typeof(Search<XXSetup.xXRequestApproval>), PersistingCheck = PXPersistingCheck.Nothing)]
public virtual bool? IsActive { get; set; }
#endregion
}
XX注册
将 PXEmailSource 属性添加到 XXRegister DAC,这是 "Assignment and Approvals Maps" 树 select 或
所必需的[PXEMailSource]
public partial class XXRegister : IBqlTable, EP.IAssign ...
根据数据库中的新字段向 XXRegister DAC 添加新属性和 classes。 XXRegister DAC 应实现 IAssign 接口(OwnerID、WorkgroupID 字段)。如果需要,使用任何其他属性。用你自己的表达方式代替三个点。
#region OwnerID
public abstract class ownerID : IBqlField { }
[PXDBGuid()]
[PXDefault(typeof(...), PersistingCheck = PXPersistingCheck.Nothing)]
[PX.TM.PXOwnerSelector()]
[PXUIField(DisplayName = "Owner")]
public virtual Guid? OwnerID { get; set; }
#endregion
#region WorkgroupID
public abstract class workgroupID : IBqlField { }
[PXDBInt]
[PXDefault(typeof(...), PersistingCheck = PXPersistingCheck.Nothing)]
[PX.TM.PXCompanyTreeSelector]
[PXUIField(DisplayName = "Workgroup", Enabled = false)]
public virtual int? WorkgroupID { get; set; }
#endregion
#region Approved
public abstract class approved : IBqlField { }
[PXDBBool]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Approved", Visibility = PXUIVisibility.Visible, Enabled = false)]
public virtual bool? Approved { get; set; }
#endregion
#region Rejected
public abstract class rejected : IBqlField { }
[PXBool]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
public bool? Rejected { get; set; }
#endregion
状态
为实体添加新的批准状态并在列表中使用它们。如果“P”和“R”已在使用,请使用其他字母。
public const string PendingApproval = "P";
public const string Rejected = "R";
public class ListAttribute : PXStringListAttribute
{
public ListAttribute() : base(
new string[] { ..., PendingApproval, Rejected, ... },
new string[] { ..., EP.Messages.PendingApproval, EP.Messages.Rejected, ... }) { ; }
}
实体图的新代码
在使用您的实体进行操作的图表中实施 EPApprovalAutomation 助手。使用您自己的参数而不是三个点。
public EPApprovalAutomation<...> Approval;
为 XXSetupApproval DAC 添加视图。用你自己的表达方式代替三个点。
public PXSelect<XXSetupApproval, Where<...>> SetupApproval;
主要设置图表的新代码
为 XXSetupApproval DAC 添加视图。
public PXSelect<APSetupApproval> SetupApproval;
根据 XXRequestApproval 字段的新值更新每个 XXSetupApproval 行。
protected virtual void XXSetup_XXRequestApproval_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
{
PXCache cache = this.Caches[typeof(XXSetupApproval)];
foreach (XXSetupApproval setup in PXSelect<XXSetupApproval>.Select(this))
{
setup.IsActive = (bool?)e.NewValue;
cache.Update(setup);
}
}
网页的新 table 和字段
XXSetup.aspx
将带有批准设置的新选项卡添加到设置的主页(XXSetup.aspx 进一步)。如果需要,使用任何其他参数。
<px:PXTabItem Text="Approval">
<Template>
<px:PXPanel ID="panelApproval" runat="server" >
<px:PXLayoutRule runat="server" LabelsWidth="S" ControlSize="XM" />
<px:PXCheckBox ID="chkXXRequestApproval" runat="server" AlignLeft="True" Checked="True" DataField="XXRequestApproval" CommitChanges="True" />
</px:PXPanel>
<px:PXGrid ID="gridApproval" runat="server" DataSourceID="ds" SkinID="Details" Width="100%" >
<AutoSize Enabled="True" />
<Levels>
<px:PXGridLevel DataMember="SetupApproval" >
<RowTemplate>
<px:PXLayoutRule runat="server" StartColumn="True" LabelsWidth="M" ControlSize="XM" />
<px:PXSelector ID="edAssignmentMapID" runat="server" DataField="AssignmentMapID" AllowEdit="True" CommitChanges="True" />
<px:PXSelector ID="edAssignmentNotificationID" runat="server" DataField="AssignmentNotificationID" AllowEdit="True" />
</RowTemplate>
<Columns>
<px:PXGridColumn DataField="AssignmentMapID" Width="250px" RenderEditorText="True" TextField="AssignmentMapID_EPAssignmentMap_Name" />
<px:PXGridColumn DataField="AssignmentNotificationID" Width="250px" RenderEditorText="True" />
</Columns>
</px:PXGridLevel>
</Levels>
</px:PXGrid>
</Template>
</px:PXTabItem>
XXRegister.aspx
将新字段“已批准”添加到实体的主页(进一步XXRegister.aspx)。如果需要,使用任何其他参数。
<px:PXCheckBox ID="chkApproved" runat="server" DataField="Approved" CommitChanges="True" Enabled="False" />
向 XXRegister.aspx 网页添加带有批准信息的新选项卡。如果需要,使用任何其他参数。
<px:PXTabItem Text="Approval Details" BindingContext="form" RepaintOnDemand="false">
<Template>
<px:PXGrid ID="gridApproval" runat="server" DataSourceID="ds" Width="100%" SkinID="DetailsInTab" NoteIndicator="True" Style="left: 0px; top: 0px;">
<AutoSize Enabled="True" />
<Mode AllowAddNew="False" AllowDelete="False" AllowUpdate="False" />
<Levels>
<px:PXGridLevel DataMember="Approval">
<Columns>
<px:PXGridColumn DataField="ApproverEmployee__AcctCD" Width="160px" />
<px:PXGridColumn DataField="ApproverEmployee__AcctName" Width="160px" />
<px:PXGridColumn DataField="ApprovedByEmployee__AcctCD" Width="100px" />
<px:PXGridColumn DataField="ApprovedByEmployee__AcctName" Width="160px" />
<px:PXGridColumn DataField="ApproveDate" Width="90px" />
<px:PXGridColumn DataField="Status" AllowNull="False" AllowUpdate="False" RenderEditorText="True"/>
<px:PXGridColumn DataField="WorkgroupID" Width="150px" />
</Columns>
</px:PXGridLevel>
</Levels>
</px:PXGrid>
</Template>
</px:PXTabItem>
自动化定义的新自动化步骤
这是批准实施过程中最困难的部分,因为应该在实体的当前行为范围内创建一些新的自动化步骤。例如,实体具有相应的下一个状态和自动化步骤:"Hold" -> "Open"。我们应该在这两个步骤之间实施审批机制。然后应该创建三个新的自动化步骤:"Hold-Open"(如果我们不需要批准文档),"Hold-Pending Approval"(如果我们需要批准文档),"Pending Approval"(从该实体应该被批准或拒绝)。新的生命周期将如下所示:"Hold" -> "Hold-Open" OR "Hold-Pending Approval" -> "Open" OR "Pending Approval"。所以 "Hold-Open" 和 "Hold-Pending Approval" 自动化步骤只是开关,决定在 "Hold" 之后应该使用哪个自动化步骤。
<Step StepID="Hold-Open" Description="Hold-Open" GraphName="…" ViewName="Document" TimeStampName="tstamp">
<Filter FieldName="Status" Condition="Equals" Value="H" Operator="And" />
<Filter FieldName="Hold" Condition="Equals" Value="False" Value2="False" Operator="And" />
<Filter FieldName="Approved" Condition="Equals" Value="True" Value2="False" Operator="And" />
<Action ActionName="*" IsDefault="1">
<Fill FieldName="Status" Value="N" />
</Action>
</Step>
<Step StepID="Hold-Pending Approval" Description="Hold-Pending Approval" GraphName="…" ViewName="Document" TimeStampName="tstamp">
<Filter OpenBrackets="1" FieldName="Status" Condition="Equals" Value="H" Operator="Or" />
<Filter FieldName="Status" Condition="Equals" Value="N" CloseBrackets="1" Operator="And" />
<Filter FieldName="Hold" Condition="Equals" Value="False" Value2="False" Operator="And" />
<Filter FieldName="Approved" Condition="Equals" Value="False" Value2="False" Operator="And" />
<Action ActionName="*" IsDefault="1">
<Fill FieldName="Status" Value="P" />
</Action>
</Step>
感谢 Acumatica 开发团队的 Evgeny Kralko 所做的工作。
将此添加为答案,因为它对于评论来说太大了。我下面的回复基于 Gabriel 的回答...
我能够获得 Gabriel 发布的使用以下添加的步骤:(参考图 SOOrderEntry 以获取示例)
- 为您创建分配和批准映射记录 screen/entity
- 需要在您的 XXSetupApproval table 中记录链接 到上面创建的批准图 ID
- 因为IAssignedMap是内部的,你需要自己创建 继承 EPApprovalAutomation 的 XXApprovalAutomation class 并覆盖 GetAssignedMaps。在您的图表上使用它代替 EP批准自动化。确保在 XXSetupApproval SetupApproval 视图之后添加它,否则您将在页面上收到类似于 "The view with type 'XXSetupApproval' must be declared inside the graph for using EPApprovalAutomation". 的错误
- 将 PXActions 添加到 "Actions" 和 "Hold" 的图形中。如果您没有执行此操作,则在尝试批准时可能会收到以下错误消息:"Automation screen/graph %GraphName% 存在但配置不正确。 找不到操作 - 'Action'"
- 为 "Approve" 或 "Reject" 菜单项添加另一个自动化步骤 操作下拉菜单。我遵循了标准销售订单“SO Pending 批准”自动化步骤作为创建自定义图形的基础 审批流程自动化步骤。
如果您想填写 EPApproval 字段,例如批准人在批准表格上看到的描述,您可以在包含批准设置的图表中附加一个缓存,如下所示:
[PXDBString(60, IsUnicode = true)] [PXDefault(typeof(MyDac.description), PersistingCheck = PXPersistingCheck.Nothing)] protected virtual void EPApproval_Descr_CacheAttached(PXCache 发送方) { }
如果您希望批准屏幕上的 "Type" 值是用户友好的,而不是对象命名空间 (PX.Objects.MyStuff.MyDac),则在主 DAC 上使用 PXCacheName 属性,例如所以:
[PXEMailSource] [可序列化] [PXCacheName("My DAC")] [PXPrimaryGraph(typeof(MyGraph))] public class MyDac : PX.Data.IBqlTable, PX.Data.EP.IAssign {...}
我的自定义图表上的自定义审批流程功能齐全。大 help/thanks 感谢 Gabriel 和 Evgeny 的这篇文章。我使用的 Acumatica 版本是 5.30.2233。一个限制是无法打包自动化步骤,因此从自定义包分发它不灵活。
如果您检查 RQRequestEntry,"Hold"
中还有一个附加代码if (order.Hold != true && order.Approved != true)
{
order.CheckBudget = false;
if (order.BudgetValidation == true)
foreach (RQBudget budget in this.Budget.Select())
{
if (budget.RequestAmt > budget.BudgetAmt)
{
order.CheckBudget = true; break;
}
}
if(order.CheckBudget == true)
{
RQRequestClass cls = this.reqclass.SelectWindowed(0,1,order.ReqClassID);
if (cls != null && cls.BudgetValidation == RQRequestClassBudget.Error)
throw new PXRowPersistedException(typeof(RQRequest).Name, order, Messages.CheckBudgetWarning);
}
if (Setup.Current.RequestAssignmentMapID != null)
{
var processor = new EPAssignmentProcessor<RQRequest>();
processor.Assign(order, Setup.Current.RequestAssignmentMapID);
order.WorkgroupID = order.ApprovalWorkgroupID;
order.OwnerID = order.ApprovalOwnerID;
}
}
yield return (RQRequest)Document.Search<RQRequest.orderNbr>(order.OrderNbr);
我一直在摸索第三级审批步骤,说明书上没有这部分。我什至尝试调试 acumatica 的代码,那里似乎没有错误。为了其他开发者的利益,这里是您所需要的
您需要将这部分代码分配给下一个审批人:
if (Setup.Current.RequestAssignmentMapID != null)
{
var processor = new EPAssignmentProcessor<RQRequest>();
processor.Assign(order, Setup.Current.RequestAssignmentMapID);
order.WorkgroupID = order.ApprovalWorkgroupID;
order.OwnerID = order.ApprovalOwnerID;
}