我想知道是否可以覆盖DefaultEndpointImpl.cs或在另一个文件中添加我自己的API逻辑?
我正在苦苦挣扎一些API调用,这些调用要求覆盖或添加此文件中的逻辑。例如,我能够通过api成功创建采购订单的采购收据,但是我无法以相同的方式添加“转移收据”采购收据。
我在API端点中包含了各种非标准字段,这些字段引用了原始的转移,转移订单和装运,但是没有成功。 API调用成功,但未添加任何行。生成行后,我已经能够更新它们的数量,但是无法添加或删除当前行。
问题似乎源于此代码,该代码似乎添加了可以正确处理添加图形的购买订单行逻辑的功能,但对其他收货类型没有任何特殊作用。
[FieldsProcessed(new[] { "POLineNbr", "POOrderType", "POOrderNbr" })]
protected void PurchaseReceiptDetail_Insert(PXGraph graph, EntityImpl entity, EntityImpl targetEntity) {
var receiptEntry = (POReceiptEntry)graph;
var lineNbr = targetEntity.Fields.SingleOrDefault(f => f.Name == "POLineNbr") as EntityValueField;
var orderType = targetEntity.Fields.SingleOrDefault(f => f.Name == "POOrderType") as EntityValueField;
var orderNbr = targetEntity.Fields.SingleOrDefault(f => f.Name == "POOrderNbr") as EntityValueField;
bool insertViaAddPO = lineNbr != null && orderNbr != null && orderType != null;
if (!insertViaAddPO && (lineNbr != null || orderType != null || orderNbr != null)) {
throw new PXException(PO.Messages.POTypeNbrLineNbrMustBeFilled);
}
var detailsCache = receiptEntry.transactions.Cache;
if (insertViaAddPO) {
receiptEntry.filter.Cache.Remove(receiptEntry.filter.Current);
receiptEntry.filter.Cache.Insert(new POReceiptEntry.POOrderFilter());
var filter = receiptEntry.filter.Current; var state = receiptEntry.filter.Cache.GetStateExt(filter, "OrderType") as PXStringState;
if (state != null && state.AllowedLabels.Contains(orderType.Value)) {
orderType.Value = state.ValueLabelDic.Single(p => p.Value == orderType.Value).Key;
}
receiptEntry.filter.Cache.SetValueExt(filter, "OrderType", orderType.Value);
receiptEntry.filter.Cache.SetValueExt(filter, "OrderNbr", orderNbr.Value);
receiptEntry.filter.Update(filter);
var orders = receiptEntry.poLinesSelection.Select().Select(r => r.GetItem<POReceiptEntry.POLineS>());
var order = orders.FirstOrDefault(o => o.LineNbr == int.Parse(lineNbr.Value));
if (order == null) {
throw new PXException(PO.Messages.PurchaseOrderLineNotFound);
}
order.Selected = true;
receiptEntry.poLinesSelection.Update(order);
receiptEntry.Actions["AddPOOrderLine2"].Press();
} else {
detailsCache.Current = detailsCache.Insert();
}
}
答案 0 :(得分:0)
经过反复的尝试,我设法使所有功能按需运行。但是,我担心的是,由于这不是记录在案的信息,因此在不久的将来可能会发生更改。
DefaultEndpointImpl类中的方法是通过反射调用的。为了为我的默认端点添加自定义功能,我扩展了默认类并为我的类和函数添加了必要的属性。
我的自定义类添加了以下内容:
第一个很简单,我对结果感到满意。第二个程序花了很多时间并调试正确,它很hacky,可能不适用于串行跟踪的项目。花费这么长时间的原因是因为有许多未知数,而我实际上一直在根据基类中的代码进行猜测。例如,我什至不确定该函数在哪个阶段触发。看起来功能完全覆盖了其他一些不可见的默认逻辑。
因此,不管它还是离开它!也许我会联系Acumatica,看看是否可以获得更多信息。
using PX.Api;
using PX.Api.ContractBased;
using PX.Api.ContractBased.Models;
using PX.Data;
using PX.Objects.PO;
using PX.Objects.IN;
using System;
using System.Linq;
using PX.Objects.CM;
using PX.Objects.CS;
namespace AcuStock
{
[PXVersion("5.30.001", "AcuStock")]
[PXVersion("6.00.001", "AcuStock")]
[PXVersion("17.200.001", "AcuStock")]
public class AcuStockEndpointImpl : PX.Objects.DefaultEndpointImpl
{
[FieldsProcessed(new[] { "POLineNbr", "POOrderType", "POOrderNbr", "OrigLineNbr", "OrigRefNbr" })]
protected new void PurchaseReceiptDetail_Insert(PXGraph graph, EntityImpl entity, EntityImpl targetEntity){
var lineNbr = targetEntity.Fields.SingleOrDefault(f => f.Name == "OrigLineNbr") as EntityValueField;
var refNbr = targetEntity.Fields.SingleOrDefault(f => f.Name == "OrigRefNbr") as EntityValueField;
var receiptQty = targetEntity.Fields.SingleOrDefault(f => f.Name == "ReceiptQty") as EntityValueField;
var location = targetEntity.Fields.SingleOrDefault(f => f.Name == "Location") as EntityValueField;
var inventoryID = targetEntity.Fields.SingleOrDefault(f => f.Name == "InventoryID") as EntityValueField;
bool insertViaAddTR = lineNbr != null && refNbr != null;
var receiptEntry = (POReceiptEntry) graph;
if (insertViaAddTR){
receiptEntry.addReceipt.Cache.Remove(receiptEntry.addReceipt.Current);
receiptEntry.addReceipt.Cache.Insert(new POReceiptEntry.POReceiptLineS());
var filter = receiptEntry.addReceipt.Current;
receiptEntry.addReceipt.Cache.SetValueExt(filter, "OrigRefNbr", refNbr.Value);
receiptEntry.addReceipt.Cache.SetValueExt(filter, "OrigLineNbr", lineNbr.Value);
receiptEntry.addReceipt.Cache.SetValueExt(filter, "InventoryID", inventoryID.Value);
receiptEntry.addReceipt.Cache.SetValueExt(filter, "ReceiptQty", receiptQty.Value);
if (location != null)
receiptEntry.addReceipt.Cache.SetValueExt(filter, "LocationID", location.Value);
receiptEntry.addReceipt.Update(filter);
var lines = receiptEntry.addReceipt.Select().Select(r => r.GetItem<POReceiptEntry.POReceiptLineS>());
var line = lines.FirstOrDefault(o => o.OrigLineNbr == int.Parse(lineNbr.Value));
if (line == null){
throw new PXException(PX.Objects.PO.Messages.PurchaseOrderLineNotFound);
}
receiptEntry.addPOReceiptLine2.Press();
} else {
base.PurchaseReceiptDetail_Insert(graph, entity, targetEntity);
}
var allocations = (targetEntity.Fields.SingleOrDefault(f => string.Equals(f.Name, "Allocations")) as EntityListField).Value ?? new EntityImpl[0];
if (allocations.Any(a => a.Fields != null && a.Fields.Length > 0)){
// Remove automatically added allocation
if (receiptEntry.splits.Current != null){
receiptEntry.splits.Delete(receiptEntry.splits.Current);
}
}
}
[FieldsProcessed(new[] { "OrigLineNbr", "OrigRefNbr", "Quantity", "Location" })]
protected void ReceiptDetails_Insert(PXGraph graph, EntityImpl entity, EntityImpl targetEntity) {
var lineNbr = targetEntity.Fields.SingleOrDefault(f => f.Name == "OrigLineNbr") as EntityValueField;
var receiptQty = targetEntity.Fields.SingleOrDefault(f => f.Name == "Quantity") as EntityValueField;
var location = targetEntity.Fields.SingleOrDefault(f => f.Name == "Location") as EntityValueField;
var allocations = (targetEntity.Fields.SingleOrDefault(f => string.Equals(f.Name, "Allocations")) as EntityListField).Value ?? new EntityImpl[0];
var hasAllocations = allocations.Any(a => a.Fields != null && a.Fields.Length > 0);
var receiptEntry = (INReceiptEntry) graph;
string transferNbr = receiptEntry.receipt.Current.TransferNbr;
var detailsCache = receiptEntry.transactions.Cache;
if (lineNbr == null || transferNbr == null){
detailsCache.Current = detailsCache.Insert();
return;
}
INTran newtran = null;
decimal newtranqty = Decimal.Parse(receiptQty.Value);
decimal newtrancost = 0m;
receiptEntry.ParseSubItemSegKeys();
using (new PXReadBranchRestrictedScope())
{
foreach (PXResult<INTransitLine, INLocationStatus2, INTransitLineLotSerialStatus, INSite, InventoryItem, INTran> res in
PXSelectJoin<INTransitLine,
InnerJoin<INLocationStatus2, On<INLocationStatus2.locationID, Equal<INTransitLine.costSiteID>>,
LeftJoin<INTransitLineLotSerialStatus,
On<INTransitLine.transferNbr, Equal<INTransitLineLotSerialStatus.transferNbr>,
And<INTransitLine.transferLineNbr, Equal<INTransitLineLotSerialStatus.transferLineNbr>>>,
InnerJoin<INSite, On<INSite.siteID, Equal<INTransitLine.toSiteID>>,
InnerJoin<InventoryItem, On<InventoryItem.inventoryID, Equal<INLocationStatus2.inventoryID>>,
InnerJoin<INTran,
On<INTran.docType, Equal<INDocType.transfer>,
And<INTran.refNbr, Equal<INTransitLine.transferNbr>,
And<INTran.lineNbr, Equal<INTransitLine.transferLineNbr>,
And<INTran.invtMult, Equal<shortMinus1>>>>>>>>>>,
Where<INTransitLine.transferNbr, Equal<Required<INTransitLine.transferNbr>>, And<INTransitLine.transferLineNbr, Equal<Required<INTransitLine.transferLineNbr>>>>,
OrderBy<Asc<INTransitLine.transferNbr, Asc<INTransitLine.transferLineNbr>>>>
.Select(receiptEntry, transferNbr, lineNbr.Value))
{
INTransitLine transitline = res;
INLocationStatus2 stat = res;
INTransitLineLotSerialStatus lotstat = res;
INSite site = res;
InventoryItem item = res;
INTran tran = res;
if (stat.QtyOnHand == 0m || (lotstat != null && lotstat.QtyOnHand == 0m))
continue;
if (newtran == null) {
if (!object.Equals(receiptEntry.receipt.Current.BranchID, site.BranchID))
{
INRegister copy = PXCache<INRegister>.CreateCopy(receiptEntry.receipt.Current);
copy.BranchID = site.BranchID;
receiptEntry.receipt.Update(copy);
}
newtran = PXCache<INTran>.CreateCopy(tran);
newtran.OrigBranchID = newtran.BranchID;
newtran.OrigTranType = newtran.TranType;
newtran.OrigRefNbr = transitline.TransferNbr;
newtran.OrigLineNbr = transitline.TransferLineNbr;
newtran.BranchID = site.BranchID;
newtran.DocType = receiptEntry.receipt.Current.DocType;
newtran.RefNbr = receiptEntry.receipt.Current.RefNbr;
newtran.LineNbr = (int)PXLineNbrAttribute.NewLineNbr<INTran.lineNbr>(receiptEntry.transactions.Cache, receiptEntry.receipt.Current);
newtran.InvtMult = (short)1;
newtran.SiteID = transitline.ToSiteID;
newtran.LocationID = transitline.ToLocationID;
newtran.ToSiteID = null;
newtran.ToLocationID = null;
newtran.BaseQty = 0m;
newtran.Qty = 0m;
newtran.UnitCost = 0m;
newtran.Released = false;
newtran.InvtAcctID = null;
newtran.InvtSubID = null;
newtran.ReasonCode = null;
newtran.ARDocType = null;
newtran.ARRefNbr = null;
newtran.ARLineNbr = null;
newtran.ProjectID = null;
newtran.TaskID = null;
newtran.CostCodeID = null;
newtran.TranCost = 0m;
receiptEntry.splits.Current = null;
newtran = receiptEntry.transactions.Insert(newtran);
receiptEntry.transactions.Current = newtran;
if (receiptEntry.splits.Current != null)
{
receiptEntry.splits.Delete(receiptEntry.splits.Current);
}
}
if (hasAllocations){
newtranqty = 0m;
foreach (var allocation in allocations) {
var newsplitqty = allocation.Fields.SingleOrDefault(f => f.Name == "Quantity") as EntityValueField;
var newsplitlocation = allocation.Fields.SingleOrDefault(f => f.Name == "Location") as EntityValueField;
INTranSplit newsplit = this.addReceiptSplitLine(receiptEntry, stat, lotstat, transitline, newtran, item, Decimal.Parse(newsplitqty.Value), newsplitlocation.Value);
newtrancost += newsplit.BaseQty.Value * newsplit.UnitCost.Value;
newtranqty += newsplit.BaseQty.Value;
}
break;
} else {
INTranSplit newsplit = this.addReceiptSplitLine(receiptEntry, stat, lotstat, transitline, tran, item, newtranqty, null);
newtrancost += newsplit.BaseQty.Value * newsplit.UnitCost.Value;
newtranqty += newsplit.BaseQty.Value;
}
}
receiptEntry.UpdateTranCostQty(newtran, newtranqty, newtrancost);
}
}
[FieldsProcessed(new[] { "OrigLineNbr" })]
protected void ReceiptAllocations_Insert(PXGraph graph, EntityImpl entity, EntityImpl targetEntity) {
// no-op
}
private INTranSplit addReceiptSplitLine(INReceiptEntry receiptEntry, INLocationStatus2 stat, INTransitLineLotSerialStatus lotstat, INTransitLine transitline, INTran tran, InventoryItem item, Decimal qty, string location){
INTranSplit newsplit;
decimal newsplitqty;
if (lotstat.QtyOnHand == null)
{
newsplit = new INTranSplit();
newsplit.InventoryID = stat.InventoryID;
newsplit.IsStockItem = true;
newsplit.FromSiteID = transitline.SiteID;
newsplit.SubItemID = stat.SubItemID;
newsplit.LotSerialNbr = null;
newsplitqty = qty;
}
else
{
newsplit = new INTranSplit();
newsplit.InventoryID = lotstat.InventoryID;
newsplit.IsStockItem = true;
newsplit.FromSiteID = lotstat.FromSiteID;
newsplit.SubItemID = lotstat.SubItemID;
newsplit.LotSerialNbr = lotstat.LotSerialNbr;
newsplitqty = qty;
}
newsplit.DocType = receiptEntry.receipt.Current.DocType;
newsplit.RefNbr = receiptEntry.receipt.Current.RefNbr;
newsplit.LineNbr = tran.LineNbr;
newsplit.SplitLineNbr = (int)PXLineNbrAttribute.NewLineNbr<INTranSplit.splitLineNbr>(receiptEntry.splits.Cache, receiptEntry.receipt.Current);
newsplit.UnitCost = 0m;
newsplit.InvtMult = (short)1;
newsplit.SiteID = transitline.ToSiteID;
newsplit.PlanID = null;
newsplit.Released = false;
newsplit.ProjectID = null;
newsplit.TaskID = null;
if (location == null) {
newsplit.LocationID = lotstat.ToLocationID ?? transitline.ToLocationID;
} else {
receiptEntry.splits.SetValueExt<INTranSplit.locationID>(newsplit, location);
}
newsplit = receiptEntry.splits.Insert(newsplit);
newsplit.MaxTransferBaseQty = newsplitqty;
newsplit.BaseQty = newsplitqty;
newsplit.Qty = newsplit.BaseQty.Value;
receiptEntry.UpdateCostSubItemID(newsplit, item);
receiptEntry.SetCostAttributes(tran, newsplit, item, tran.OrigRefNbr);
newsplit.UnitCost = PXCurrencyAttribute.BaseRound(receiptEntry, newsplit.UnitCost);
receiptEntry.splits.Update(newsplit);
return newsplit;
}
}
}