I have a non persisted field in my Sales Order grid. I want the use to enter a value which will be used to update the unit price. i have tried catching all of the events for the grid/field but non of them trigger when the user enters a value. I do not need the update to happen on every character, just when the user hits tab to exist the field or enter.
Graph Extension:
using PX.Data;
using PX.Objects.CS;
using PX.Objects.IN;
namespace PX.Objects.SO
{
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
{
protected void SOLine_UsrMargin_FieldSelecting(PXCache cache, PXFieldSelectingEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
protected void SOLine_UsrMargin_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
protected void SOLine_UsrMargin_FieldUpdating(PXCache cache, PXFieldUpdatingEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
public class string_PROMODET : Constant<string>
{
public string_PROMODET() : base("PROMODET") { }
}
public class string_SALESPROMO : Constant<string>
{
public string_SALESPROMO() : base("SALESPROMO") { }
}
protected void SOLine_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
protected void SOLine_RowUpdating(PXCache cache, PXRowUpdatingEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
protected void SOLine_RowInserted(PXCache cache, PXRowInsertedEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
protected void SOLine_RowInserting(PXCache cache, PXRowInsertingEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
protected void SOLine_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
protected void SOLine_RowSelecting(PXCache cache, PXRowSelectingEventArgs e)
{
var salesOrderEntry = (SOLine)e.Row;
if (salesOrderEntry == null)
return;
UpdateCustomFields(cache, salesOrderEntry);
}
private static void UpdateCustomFields(PXCache cache, SOLine salesOrderEntry)
{
SOLineExt soLineExt = PXCache<SOLine>.GetExtension<SOLineExt>(salesOrderEntry);
PXUIFieldAttribute.SetEnabled<SOLineExt.usrSalesPromotion>(cache, salesOrderEntry, false);
PXUIFieldAttribute.SetEnabled<SOLineExt.usrSalesPromotionDetails>(cache, salesOrderEntry, false);
using (new PXConnectionScope())
{
InventoryItem ii = PXSelect<InventoryItem, Where<InventoryItem.inventoryID, Equal<Required<SOLine.inventoryID>>>>
.Select(new PXGraph(), salesOrderEntry.InventoryID);
if (ii != null)
{
CSAnswers promotionDetail = PXSelect<CSAnswers,
Where2<
Where<CSAnswers.refNoteID, Equal<Required<InventoryItem.noteID>>>,
And<Where<CSAnswers.attributeID, Equal<string_PROMODET>,
Or<CSAnswers.attributeID, Equal<string_PROMODET>>>>>>
.Select(new PXGraph(), ii.NoteID);
CSAnswers promotion = PXSelect<CSAnswers,
Where2<
Where<CSAnswers.refNoteID, Equal<Required<InventoryItem.noteID>>>,
And<Where<CSAnswers.attributeID, Equal<string_SALESPROMO>,
Or<CSAnswers.attributeID, Equal<string_SALESPROMO>>>>>>
.Select(new PXGraph(), ii.NoteID);
INItemStats itemStats = PXSelect<INItemStats, Where<INItemStats.inventoryID, Equal<Required<SOLine.inventoryID>>>>
.Select(new PXGraph(), salesOrderEntry.InventoryID);
if (itemStats != null)
{
cache.SetValue<SOLineExt.usrLastCost>(salesOrderEntry, itemStats.LastCost);
cache.SetValue<SOLineExt.usrMargin>(salesOrderEntry, ((salesOrderEntry.CuryUnitPrice / itemStats.LastCost) - 1) * 100);
}
if (promotion != null)
{
cache.SetValue<SOLineExt.usrSalesPromotion>(salesOrderEntry, promotion.Value == "1" ? true : false);
cache.SetValue<SOLineExt.usrSalesPromotionDetails>(salesOrderEntry, promotion.Value == "1" ? promotionDetail.Value : "");
}
}
}
}
}
}
Cache Extension:
using PX.Data;
using System;
namespace PX.Objects.SO
{
public class SOLineExt : PXCacheExtension<PX.Objects.SO.SOLine>
{
#region UsrLastCost
[PXDecimal]
[PXUIField(DisplayName="Last Cost", Enabled = false, Visible = true, IsReadOnly = true)]
public virtual Decimal? UsrLastCost { get; set; }
public abstract class usrLastCost : IBqlField { }
#endregion
#region UsrSalesPromotion
[PXBool]
[PXUIField(DisplayName="Sales Promotion", Enabled = false, IsReadOnly = true)]
public virtual bool? UsrSalesPromotion { get; set; }
public abstract class usrSalesPromotion : IBqlField { }
#endregion
#region UsrSalesPromotionDetails
[PXString(64)]
[PXUIField(DisplayName="Sales Promotion Details", Enabled = false, IsReadOnly = true)]
public virtual string UsrSalesPromotionDetails { get; set; }
public abstract class usrSalesPromotionDetails : IBqlField { }
#endregion
#region UsrMargin
[PXDecimal]
[PXUIField(DisplayName="Margin")]
public virtual Decimal? UsrMargin { get; set; }
public abstract class usrMargin : IBqlField { }
#endregion
}
}
Related
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Common;
using PX.Data;
using PX.Objects.GL;
using PX.Objects.CM;
using PX.Objects.CS;
using PX.Objects.CR;
using PX.Objects.TX;
using PX.Objects.IN;
using PX.Objects.EP;
using PX.Objects.AP;
using PX.Objects.AR;
using PX.Objects.SO;
using PX.TM;
using SOOrder = PX.Objects.SO.SOOrder;
using SOLine = PX.Objects.SO.SOLine;
using PX.CS.Contracts.Interfaces;
using PX.Data.DependencyInjection;
using PX.Data.ReferentialIntegrity.Attributes;
using PX.Objects.PM;
using CRLocation = PX.Objects.CR.Standalone.Location;
using PX.Objects.AP.MigrationMode;
using PX.Objects.Common;
using PX.Objects.Common.Discount;
using PX.Objects;
using PX.Objects.PO;
using PX.Objects.CT;
using PX.Data.EP;
namespace PX.Objects.PO
{
public class POOrderEntry_Extension : PXGraphExtension<POOrderEntry>
{
#region Event Handlers
[Serializable]
public class ProjectFilter : IBqlTable
{
#region ContractID
public abstract class contractID : PX.Data.IBqlField { }
//[PXDefault(typeof(PMProject.contractID))]
[PXUIField(DisplayName = "Project ID")]
[Project(DescriptionField = typeof(PMProject.contractCD))]
public int? ContractID { get; set; }
#endregion
#region ProjectTaskID
public abstract class projectTaskID : PX.Data.BQL.BqlInt.Field<projectTaskID> { }
protected Int32? _ProjectTaskID;
[ProjectTask(typeof(PMProject.contractID), AlwaysEnabled = true, DirtyRead = true, IsKey = true)]
public virtual Int32? ProjectTaskID
{
get
{
return this._ProjectTaskID;
}
set
{
this._ProjectTaskID = value;
}
}
#endregion
}
//PXSelect<PMCostBudget, Where<PMCostBudget.projectID, Equal<Current<PMProject.contractID>>, And<PMCostBudget.type, Equal<GL.AccountType.expense>,
// And<Where<Current<CostBudgetFilter.projectTaskID>, IsNull, Or<Current<CostBudgetFilter.projectTaskID>, Equal<PMCostBudget.projectTaskID>>>>>>,
// OrderBy<Asc<PMCostBudget.projectID, Asc<PMCostBudget.projectTaskID, Asc<PMCostBudget.inventoryID, Asc<PMCostBudget.costCodeID, Asc<PMCostBudget.accountGroupID>>>>>>>(this);
//PXDelegateResult delResult = new PXDelegateRes
public PXFilter<ProjectFilter> projectfilter;
[PXFilterable]
[PXCopyPasteHiddenView]
public PXSelect<PMCostBudget,
Where<PMCostBudget.projectID, Equal<Current<ProjectFilter.contractID>>,
//And<PMCostBudget.projectTaskID, Equal<Current<ProjectFilter.projectTaskID>>,
//And<PMProject.locationID, Equal<Current<POOrder.vendorLocationID>>,
And<PMCostBudget.type, Equal<GL.AccountType.expense>>>> getCostBudget;
// public PXOrderedSelect<POOrder, POLine, Where<POLine.orderType, Equal<Current<POOrder.orderType>>, And<POLine.orderNbr, Equal<Optional<POOrder.orderNbr>>>>, OrderBy<Asc<POLine.orderType, Asc<POLine.orderNbr, Asc<POLine.sortOrder, Asc<POLine.lineNbr>>>>>> Transactions;
// PX.Objects.PM.PMProject project = PXSelect<PM.PMProject, Where<PM.PMProject.contractID, Equal<Required<PM.PMProject.contractID>>>>.Select(this, location.Current.VDefProjectID);
//if (project != null)
public PXAction<POOrder> AddProjectCostBudget;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Add Project Cost Budget")]
public virtual IEnumerable addProjectCostBudget(PXAdapter adapter)
{
if (getCostBudget.AskExt() == WebDialogResult.OK)
{
return addSelCostBudget(adapter);
}
return adapter.Get();
}
public PXAction<POOrder> AddSelCostBudget;
[PXUIField(DisplayName = "Add", Visible = false)]
[PXButton(CommitChanges = true)]
public virtual IEnumerable addSelCostBudget(PXAdapter adapter)
{
//Base.Transactions.Cache.ForceExceptionHandling = true;
foreach (PMCostBudget cost in getCostBudget.Cache.Cached)
{
//var costExt = cost.GetExtension<PMBudgetExt>();
if (cost.Selected == true)
{
POLine newline = Base.Transactions.Insert();
newline.ProjectID = cost.ProjectID;
newline.TaskID = cost.ProjectTaskID;
newline.CostCodeID = cost.CostCodeID;
newline.InventoryID = cost.InventoryID;
newline.UOM = cost.UOM;
Base.Transactions.Cache.Update(newline);
Base.Transactions.Update(newline);
}
}
//getCostBudget.Cache.Clear();
return adapter.Get();
}
//public override void Initialize()
//{
// base.Initialize();
// AddProjectCostBudget.SetEnabled(false);
//}
//protected virtual void PMCostBudget_ProjectTaskID_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
//{
// PMCostBudget row = e.Row as PMCostBudget;
// if (row == null) return;
// if (!(e.NewValue is Int32)) return;
// if (e.NewValue != null)
// {
// PXResultset<INLocation> projectLocations = PXSelectReadonly<INLocation,
// Where<INLocation.projectID, Equal<Required<INLocation.projectID>>,
// And2<Where<INLocation.taskID, IsNull>, Or<INLocation.taskID, Equal<Required<INLocation.taskID>>>>>>.Select(Base, row.ProjectID, e.NewValue);
// string taskCD = null;
// PMTask task = PXSelect<PMTask, Where<PMTask.taskID,
// Equal<Required<PMTask.taskID>>>>.Select(Base, row.TaskID);
// if (task != null)
// {
// taskCD = task.TaskCD;
// }
// else
// {
// sender.RaiseExceptionHandling<PMCostBudget.projectTaskID>(row, taskCD, new PXSetPropertyException(Messages.ProjectTaskIsNotAssociatedWithAnyInLocation, PXErrorLevel.Warning));
// }
// }
//}
//protected virtual void PMCostBudget_ProjectTaskID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
//{
// PMCostBudget cost = e.Row as PMCostBudget;
// if (cost == null) return;
// PMTask task = PXSelect<PMTask,
// Where<PMTask.projectID, Equal<Current<ProjectFilter.contractID>>,
// And<PMTask.isDefault, Equal<True>>>>.Select(Base, cost.ProjectID, cost.ProjectTaskID);
// if (task == null) return;
// sender.SetValue<PMCostBudget.projectTaskID>(cost, task.TaskID);
//}
#endregion
}
}
I had created a pop-up panel to insert Project Cost budget into POLines in Purchase Order screen. every time I want to select and insert, It gives this error
Error: An error occurred during processing of the field Project Task: Error: 'Project Task' cannot be found in the system.
The code snippet of my view:[
[Serializable]
public class ProjectFilter : IBqlTable
{
#region ContractID
public abstract class contractID : PX.Data.IBqlField { }
//[PXDefault(typeof(PMProject.contractID))]
[PXUIField(DisplayName = "Project ID")]
[Project(DescriptionField = typeof(PMProject.contractCD))]
public int? ContractID { get; set; }
#endregion
#region ProjectTaskID
public abstract class projectTaskID : PX.Data.BQL.BqlInt.Field<projectTaskID> { }
protected Int32? _ProjectTaskID;
[ProjectTask(typeof(PMProject.contractID), AlwaysEnabled = true, DirtyRead = true, IsKey = true)]
public virtual Int32? ProjectTaskID
{
get
{
return this._ProjectTaskID;
}
set
{
this._ProjectTaskID = value;
}
}
#endregion
}
public PXFilter<ProjectFilter> projectfilter;
[PXFilterable]
[PXCopyPasteHiddenView]
public PXSelect<PMCostBudget,
Where<PMCostBudget.projectID, Equal<Current<ProjectFilter.contractID>>,
And<PMCostBudget.projectTaskID, Equal<Current<ProjectFilter.projectTaskID>>,
And<PMCostBudget.type, Equal<GL.AccountType.expense>>>>> getCostBudget;
]1 this is the error image
The ProjectTask attribute expects a reference to the currently selected project; you need to use ProjectFilter.projectID instead of PMProject.projectID
Build 18.203.0006
Page: AP301000
Good day, I have extended the APRegister Class by adding 2 new checkbox fields. I want to iterate through al the APTran transactions and look for suIDs that start with FBL and GAS. If I find them the new tick boxes should tick.
Currently, the fields(tick boxes) do not save to the database. I am not sure how to tell Acumatica the APRegisterExt has updated.
APInvoiceEntry_Extension:
namespace PX.Objects.AP
{
public class APRegisterExt : PXCacheExtension<PX.Objects.AP.APRegister>
{
#region UsrGroupAEmail
[PXDBBool]
[PXUIField(DisplayName="GroupA Email")]
public virtual bool? UsrGroupAEmail { get; set; }
public abstract class usrGroupAEmail : IBqlField { }
#endregion
#region UsrGroupBEmail
[PXDBBool]
[PXUIField(DisplayName="GroupB Email")]
public virtual bool? UsrGroupBEmail { get; set; }
public abstract class usrGroupBEmail : IBqlField { }
#endregion
}
}
APInvoiceEntry_Extension:
namespace PX.Objects.AP
{
public class APInvoiceEntry_Extension : PXGraphExtension<APInvoiceEntry>
{
#region Event Handlers
protected void APInvoice_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
APInvoice invoice = e.Row as APInvoice;
if (invoice == null) return;
var apRX = invoice.GetExtension<APRegisterExt>();
PXResultset<APTran> Tlist = PXSelectJoin<APTran,
LeftJoin<POReceiptLine,
On<POReceiptLine.receiptNbr, Equal<APTran.receiptNbr>,
And<POReceiptLine.lineNbr, Equal<APTran.receiptLineNbr>>>>,
Where<
APTran.tranType, Equal<Current<APInvoice.docType>>,
And<APTran.refNbr, Equal<Current<APInvoice.refNbr>>>>,
OrderBy<
Asc<APTran.tranType,
Asc<APTran.refNbr,
Asc<APTran.lineNbr>>>>>.Select(Base);
apRX.UsrGroupBEmail = false;
apRX.UsrGroupAEmail = false;
foreach (APTran item in Tlist)
{
if (item.SubID.Value.ToString().StartsWith("FBL") || item.SubID.Value.ToString().StartsWith("GAS"))
{
apRX.UsrGroupBEmail = true;
cache.SetValue<APRegisterExt.usrGroupBEmail>(e.Row, true);
}
else
{
apRX.UsrGroupAEmail = true;
}
}
}
#endregion
}
}
Can someone please show me the correct way of saving the data to the new tick boxes so that cache updates.
Consider moving the logic to APRegister_RowPersisting.
Importantly, APTran.subID is an Int dataType.
Read instead the Sub table/DAC during a For Loop of
Base.Transactions.Select() to detect SubCD startsWith FBL or GAS.
foreach(APTran item in Base.Transaction.Select())
{
Sub sub = PXSelect<Sub,
Where<Sub.subID, Equal<Required<Sub.subID>>>>
.Select(graph, item.SubID);
if (item.SubCD.StartsWith("FBL") ||
item.SubCD.StartsWith("GAS"))
{
apRX.UsrGroupBEmail = true;
}
else
{
apRX.UsrGroupAEmail = true;
}
}
To be complete, you may also need to reset both flags during APTran_SubID_FieldUpdated regardless of the changed value:
protected void APTran_SubID_FieldUpdated(PXCache sender,
PXFieldUpdatedEventArgs e, PXFieldUpdated del)
{
del?.Invoke(sender,e);
var apRX = Base.Document.Current.GetExtension<APRegisterExt>();
apRX.UsrGroupBEmail = false;
apRX.UsrGroupAEmail = false;
}
I have a bound custom field grossprofit added into the SOLine grid which is calculated based on Item UnitCost, AverageCost and Qty.
I have the code written into SOLine_CuryUnitPrice_FieldSelecting event. However, it is not saving into the Database.
Also, I need a total of all lineitems for the custom field as a TotalGrossProfit on Order summary. It is calculating but for some reason it is not reflecting on screen.
Can anyone suggest?
Here is the code
public class SOOrderExtension : PXCacheExtension<SOOrder>
{
#region UsrTotalGrossProfit
public abstract class usrTotalGrossProfit : PX.Data.IBqlField
{
}
protected Decimal? _UsrTotalGrossProfit;
[PXCurrency(typeof(SOOrder.curyInfoID), typeof(SOOrder.orderWeight))]
[PXDefault(TypeCode.Decimal, "0.0")]
[PXUIField(DisplayName = "Total Gross Profit")]
public virtual Decimal? UsrTotalGrossProfit
{
get
{
return this._UsrTotalGrossProfit;
}
set
{
this._UsrTotalGrossProfit = value;
}
}
#endregion
}
public class SOLineExtension : PXCacheExtension<SOLine>
{
#region UsrGrossProfit
public abstract class usrGrossProfit : PX.Data.IBqlField
{
}
protected Decimal? _UsrGrossProfit;
[PXDBCurrency(typeof(SOOrder.curyInfoID), typeof(SOOrder.discTot))]
[PXDefault(TypeCode.Decimal, "0.0")]
[PXUIField(DisplayName = "Gross Profit")]
public virtual Decimal? UsrGrossProfit
{
get
{
return this._UsrGrossProfit;
}
set
{
this._UsrGrossProfit = value;
}
}
#endregion
}
public class SOOrderEntryExtension : PXGraphExtension<SOOrderEntry>
{
protected virtual void SOOrder_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
SOOrder row = e.Row as SOOrder;
if (row == null) return;
SOOrderExtension orderExtension = PXCache<SOOrder>.GetExtension<SOOrderExtension>(row);
foreach (SOLine soLine in Base.Transactions.Select())
{
SOLineExtension lineItem = PXCache<SOLine>.GetExtension<SOLineExtension>(soLine);
orderExtension.UsrTotalGrossProfit = orderExtension.UsrTotalGrossProfit + lineItem.UsrGrossProfit;
}
}
protected void SOLine_CuryUnitPrice_FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
var row = (SOLine)e.Row;
if (row != null && Base.Document.Current != null && Base.Document.Current.Status != "C")
{
SOLineExtension opportunity = PXCache<SOLine>.GetExtension<SOLineExtension>(row);
InventoryItem inv = PXSelect<InventoryItem,
Where<InventoryItem.inventoryID, Equal<Required<InventoryItem.inventoryID>>>>.Select(new PXGraph(), row.InventoryID);
if (inv.ItemType == "F") // Stock Item
{
opportunity.UsrGrossProfit = (row.UnitPrice - invc.AvgCost) * row.Qty;
}
Base.Save.Press();
Base.Persist();
}
}
}
These are the two events that I would use.. you may have to change them to your version of C# i am using 7...
protected void SOLine_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
if (!e.row is SOLine row) return;
if (!e.oldRow is SOLine oldRow) return;
//check for unwanted status, if true return
if (Base.Document.Current.Status == "C") return;
//check for the fields to have value, if no return
if (!row.UnitPrice.HasValue || !row.Qty.HasValue) return;
//get row extension
var rowExt = row..GetExtension<SOLineExtension>();
//select inventory record
var invItem = (InventoryItem)PXSelect<InventoryItem,
Where<InventoryItem.inventoryID, Equal<Required<InventoryItem.inventoryID>>>>.Select(Base, row.InventoryID);
if (invItem == null) return;
//add value to field, no persist or save
if (inv.ItemType == "F") // Stock Item
{
rowExt.UsrGrossProfit = (row.UnitPrice - invc.AvgCost) * row.Qty;
}
}
protected virtual void SOOrder_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
//this may not work in older versions of C#
if (!(e.row is SOOrder row) return;
var rowExt = row.GetExtension<SOOrderExtension>();
foreach (SOLine soLine in Base.Transactions.Select())
{
var lineItem = soLine.GetExtension<SOLineExtension>();
rowExt.UsrTotalGrossProfit += lineItem.UsrGrossProfit;
}
//this is probably why not showing up...
Base.Document.Cache.Update(Base.Document.Current);
}
I have a requirement to have a field on SalesOrder screen and the same field should appear on Shipment screen also for respective SalesOrder. And the user should be able to update these field on both the screen.
I created a bound field on Sales Order screen which user can save it. Then I created an unbound field on Shipment screen to show the text from Sales Order. For that I have written a SOShipment_RowSelected event and later for user to update it to the database, I have written SOShipment_RowUpdated. However, when I try to edit the field, it fires RowSelected event and it overwrites the editing and bring back in the same original value.
I have tried with SOShipment_ShipmentNbr_FieldUpdated & SOShipment_ShipmentNbr_FieldUpdating event but its not firing everytime.
Here is the code for Cache extension-
public class SOOrderExtension : PXCacheExtension<SOOrder>
{
#region UsrNotesText
[PXDBString(255)]
[PXUIField(DisplayName = "Pick List Notes")]
public virtual string UsrNotesText { get; set; }
public abstract class usrNotesText : IBqlField { }
#endregion
}
public class SOShipmentExtension : PXCacheExtension<SOShipment>
{
#region UsrNotesText
[PXString(255)]
[PXUIField(DisplayName = "Pick List Notes")]
public virtual string UsrNotesText { get; set; }
public abstract class usrNotesText : IBqlField { }
#endregion
}
SOShipmentExtension code-
public class SOShipmentEntryExtension : PXGraphExtension<SOShipmentEntry>
{
PXSelect<SOOrder> soOrder;
protected virtual void SOShipment_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
if (e.Row != null)
{
SOOrder order = PXSelectJoin<SOOrder,
LeftJoin<SOOrderShipment, On<SOOrder.orderNbr, Equal<SOOrderShipment.orderNbr>,
And<SOOrder.orderType, Equal<SOOrderShipment.orderType>>>,
LeftJoin<SOShipment, On<SOOrderShipment.shipmentNbr, Equal<SOShipment.shipmentNbr>>>>,
Where<SOShipment.shipmentNbr, Equal<Current<SOShipment.shipmentNbr>>>>.Select(Base);
if (order != null)
{
SOOrderExtension orderExt = PXCache<SOOrder>.GetExtension<SOOrderExtension>(order);
SOShipment soShipment = Base.Document.Current;
SOShipmentExtension ext = PXCache<SOShipment>.GetExtension<SOShipmentExtension>(soShipment);
ext.UsrNotesText = orderExt.UsrNotesText;
}
}
}
protected virtual void SOShipment_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
SOShipment oldRow = (SOShipment)e.OldRow;
SOShipment newRow = (SOShipment)e.Row;
if (oldRow != null || newRow != null)
{
SOShipmentExtension oldExt = PXCache<SOShipment>.GetExtension<SOShipmentExtension>(oldRow);
SOShipmentExtension newExt = PXCache<SOShipment>.GetExtension<SOShipmentExtension>(newRow);
if (oldExt.UsrNotesText != newExt.UsrNotesText)
{
{
SOOrder order = PXSelectJoin<SOOrder,
LeftJoin<SOOrderShipment, On<SOOrder.orderNbr, Equal<SOOrderShipment.orderNbr>,
And<SOOrder.orderType, Equal<SOOrderShipment.orderType>>>,
LeftJoin<SOShipment, On<SOOrderShipment.shipmentNbr, Equal<SOShipment.shipmentNbr>>>>,
Where<SOShipment.shipmentNbr, Equal<Current<SOShipment.shipmentNbr>>>>.Select(Base);
soOrder.Current = order;
if (order != null)
{
SOOrderExtension orderExt = PXCache<SOOrder>.GetExtension<SOOrderExtension>(order);
orderExt.UsrNotesText = newExt.UsrNotesText;
soOrder.Update(order);
}
}
}
}
}
}
Any suggestions?
The trick is to initialize UsrNotesText elsewhere.
You can use PXDefault attribute:
[PXDefault(typeof(Search<SOOrderExtension.usrNotesText, Where< [...] >>))]
Or FieldDefaulting event handler:
public void SOShipment_UsrNotesText_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
e.NewValue = [...]
}
Sometimes you also want to re-initialize when user changes key fields that are not re-triggering the default.:
public void SOShipment_ShipmentNbr_FieldUpdated(PXCache sender, PXFieldDefaultingEventArgs e)
{
SOShipment shipment = e.Row as SOShipment;
if (shipment != null)
{
SOShipmentExtension shipmentExt = PXCache<SOShipment>.GetExtension<SOShipmentExtension>(shipment);
if (shipmentExt != null)
{
shipmentExt.UsrNotesText = [...];
}
}
}
In such case manually re-triggering FieldDefaulting event with RaiseFieldDefaulting is often a better option.
However method you choose to initialize avoid setting the field value in RowSelected because that event is called at times when you don't want to initialize the custom field.
While creating GI for sales order screen I want to display the total number of lines in document details tab. Can anyone suggest a way to start implementing this?
After including the custom field in GI it doesn't populate the column with data.
The code for printing the row count is as below which is also discussed in Adding custom button in acumatica
public void SOOrder_UsrTotalTransactions_FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
e.ReturnValue = GetTotalTransactions(sender);
}
// Update values
public void SOLine_RowDeleted(PXCache sender, PXRowDeletedEventArgs e)
{
UpdateTotals(sender, e.Row as SOOrder, true);
}
public void SOLine_RowInserted(PXCache sender, PXRowInsertedEventArgs e)
{
UpdateTotals(sender, e.Row as SOOrder, true);
}
public void SOLine_OrderQty_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
UpdateTotals(sender, e.Row as SOOrder, false);
}
public void UpdateTotals(PXCache sender, SOOrder soOrder, bool isUpdateTranCount)
{
// Get SOOrder DAC extension
if (soOrder != null)
{
SOOrderExt soOrderExt = sender.GetExtension<SOOrderExt>(soOrder);
if (soOrderExt != null)
{
if (isUpdateTranCount)
{
sender.SetValueExt<SOOrderExt.usrTotalTransactions>(soOrder, GetTotalTransactions(sender));
}
}
}
}
public int? GetTotalTransactions(PXCache sender)
{
return Base.Transactions.Select().Count();
}
}
}
the DAC code is:
[PXDBInt]
[PXUIField(DisplayName="Total Lines", Enabled = false)]
If you are trying to set the value I would try a simplified version of your example like this...
namespace PX.Objects.SO
{
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public void SOLine_RowDeleted(PXCache sender, PXRowDeletedEventArgs e)
{
UpdateTotals(sender, e.Row as SOOrder);
}
public void SOLine_RowInserted(PXCache sender, PXRowInsertedEventArgs e)
{
UpdateTotals(sender, e.Row as SOOrder);
}
public void UpdateTotals(PXCache sender, SOOrder soOrder)
{
if (soOrder != null)
{
SOOrderExt soOrderExt = sender.GetExtension<SOOrderExt>(soOrder);
if (soOrderExt != null)
{
sender.SetValueExt<SOOrderExt.usrRowCount>(soOrder, GetRowCount());
}
}
}
public int GetRowCount()
{
return Base.Transactions?.Select().Count() ?? 0;
}
}
}
You would use FieldSelecting to set unbound field values. Because your field is bound you do not want to call fieldselecting for your example.