研究
POReceiptLine 上的 AllowOpen 字段是 PXBool。这意味着该值必须通过 PXDBScalar、PXFormula 等或通过图中的某些业务逻辑来填充。要了解发生了什么,让我们看看 POReceiptLine 的 DAC...
#region AllowOpen
public abstract class allowOpen : PX.Data.BQL.BqlBool.Field<allowOpen> { }
protected Boolean? _AllowOpen;
[PXBool()]
[PXUIField(DisplayName = "Open PO Line", Visibility = PXUIVisibility.Service, Visible = true)]
public virtual Boolean? AllowOpen
{
get
{
return this._AllowOpen;
}
set
{
this._AllowOpen = value;
}
}
#endregion
如您所见,DAC 中的该字段没有任何逻辑,因此我们需要转向图表来了解它是如何使用的。 (即使 DAC 中存在逻辑,我们也需要查看图表是否执行某些操作。但是,DAC 中的逻辑可能很容易被 CacheAttached 覆盖 - 不幸的是,在这种情况下并非如此。)
让我们转向处理返回的POReceiptEntry。我们发现在 POReceiptLine_RowSelected 事件中设置了 AllowComplete 和 AllowOpen,正如我们所期望的,因为它必须填充在 DAC 中没有逻辑的代码的图形端。
if ((row.AllowComplete == null || row.AllowOpen == null) && fromPO)
{
POLineR source = PXSelect<POLineR,
Where<POLineR.orderType, Equal<Required<POLineR.orderType>>,
And<POLineR.orderNbr, Equal<Required<POLineR.orderNbr>>,
And<POLineR.lineNbr, Equal<Required<POLineR.lineNbr>>>>>>
.Select(this, row.POType, row.PONbr, row.POLineNbr);
// Acuminator disable once PX1047 RowChangesInEventHandlersForbiddenForArgs [Legacy, moved the exception here from PX.Objects.acuminator because the condition was changed]
row.AllowComplete = row.AllowOpen = (row.Released == true) ?
(row.ReceiptType != POReceiptType.POReturn ? source?.Completed == true : source?.Completed != true) :
(source?.AllowComplete ?? false);
该字段填充在 row.AllowComplete = row.AllowOpen = (row.Released == true) ?... 部分代码中。
随后,我们看到 CopyFromOrigReceiptLine 方法在正在创建的“destLine”上将此值设置为 false。
destLine.AllowOpen = false;
由于这不是“真实的”,所以我们知道这不是我们的位置。继续,我们在 UpdatePOLineCompletedFlag 中看到 AllowComplete 和 AllowOpen 正在设置。这可能是我们的位置(或其中之一)。
row.AllowComplete = row.AllowOpen = poLineCurrent.AllowComplete;
旁注:值得注意的是,这一行在 if then else 中出现了两次。在这两种情况下,它都会被执行,因此最好将这个相同的语句放在 if then else 之后,因为无论 if 和 else 条件如何,都会执行相同的语句。 p>
这种特殊用途似乎是从正在接收的采购订单行的 AllowComplete 字段中提取值。 此时,您应该考虑是否需要在采购订单行上游查看是否也需要操作那里的字段。我无法为您回答这个问题,因为您的业务案例将推动决策。
Copy 方法中还有一行设置了 AllowComplete 和 AllowOpen。
aDest.AllowComplete = aDest.AllowOpen = (aSrc.CompletePOLine == CompletePOLineTypes.Quantity);
Copy 方法被重载,并且该方法的另一个签名将值设置为 true。
aDest.AllowComplete = true;
aDest.AllowOpen = true;
这两种情况也可能需要定制,但我认为这不是主要问题。
后续步骤
此时,我们看到该字段被设置在 UpdatePOLineCompletedFlag 或似乎与复制记录相关的方法中。如果与 copy 相关的方法也需要更改,您将需要进一步调查。但是,我认为最初的重点应该放在 UpdatePOLineCompletedFlag 方法上。
如果我们发现确定的其他点需要自定义,我们可能会以相同的方式处理它们...覆盖基本方法/事件,在我们的覆盖中调用原始方法/事件,然后强制值适合我们的商业案例。需要仔细测试,因为强行更改这些值可能会产生无法预料的负面影响。
尝试一下
我们想要更新(或创建)POReceiptEntry 的图形扩展以覆盖 UpdatePOLineCompleteFlag 方法。这可以编译,但我完全未经测试。我们需要创建一个委托并指定 PXOverride 属性。然后我们要在覆盖相关字段之前执行基本方法。
请注意额外的代码(已注释掉),以提醒您注意更新缓存中记录的方法(通常是事件)并需要定位,以免我们使用过时的副本的记录。我认为在这种情况下没有必要,但是在我看到的代码示例中似乎有些晦涩难懂。当然,那是因为我一直在查看很少有图形扩展覆盖事件处理程序的代码存储库!
#region CreateReceiptEntry Override
public delegate void UpdatePOLineCompleteFlagDelegate(POReceiptLine row, bool isDeleted, POLine aOriginLine);
[PXOverride]
public virtual void UpdatePOLineCompleteFlag(POReceiptLine row, bool isDeleted, POLine aOriginLine, UpdatePOLineCompleteFlagDelegate baseMethod)
{
//Execute original logic
baseMethod(row, isDeleted, aOriginLine);
/* If the base method has updated the cache, then we would need to locate the updated record in the cache to proceed
* This tends to be the case more often with event handlers, so it probably isn't needed in this case.
* This is just for reference as a training reminder
//If row has been updatd in the baseMethod, let's go get the updated cache values
POReceiptLine locateRow = Base.transactions.Locate(row);
if (locateRow != null) row = locateRow;
*/
//Override the fields to false - need to test to see if this creates any issues with breaking existing business logic
row.AllowComplete = row.AllowOpen = false;
}
#endregion
如果这不能为您提供所需的具体答案,我希望它至少能让您对如何寻找“现场”进行更改有所了解。我怀疑您可能需要更新 POLine 以获得完整的解决方案,如上所述。 (请参阅事件处理程序 POReceiptLine_AllowOpen_FieldUpdated 了解导致我得出该结论的代码。)
祝你的定制好运,编码愉快!