How would you write code to set a default value on a grid with the value of the field from the line above it?
One way would be this. Let us suppose you want to default the quantity on the Bills and Adjustments screen, with the quantity from the prior line. Consider using the pattern below.
public class APInvoiceEntry_Extension : PXGraphExtension<APInvoiceEntry>
{
#region Event Handlers
protected void APTran_Qty_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs e)
{
var row = (APTran)e.Row;
if (row == null) return;
// get prior qty and default it here, unless it is already set.
if (row.Qty == null)
{
decimal? priorQty = GetPriorQtyInGrid(row);
if (priorQty != null)
{
e.NewValue = priorQty;
}
}
}
#endregion
#region Functions
public decimal? GetPriorQtyInGrid(APTran currentRow)
{
APTran lastline = null;
foreach (APTran line in Base.Transactions.Select())
{
if (currentRow == line)
{
break;
}
lastline = line;
}
if (lastline != null)
return lastline.Qty;
else
return null;
}
#endregion
}
Related
Anyone know if it's possible to combine a field like Item Class (we use a 3 letter code for each one) with a sequential number to get a unique Inventory ID?
e.g. we need all hardware to be HWR-00988 but all Shipping Supplies to be SUP-00989 and so on.
My workaround right now is to create an Attribute called ITEMCLASS and basically mirror the item class codes (HWR, SUP, etc) then add attributes to each Item Class and use the Inventory ID Segment Settings to make it look like it's pulling the actual Item Class.
Seems like this should exist though? I know the data exists in INITEMMENU already.
If you mean having a unique InventoryCD key that switches between constants HWR-XXXXX and SUP-XXXXX based on custom business rules (like appending Item Class); I don't think that's possible out-of-box without programming.
Usually this is accomplished with a custom attribute. Here's an example for [CuryID] attribute which computes key value based on arbitrary logic.
Usage, decorate key fields with custom attribute [CuryID]:
[PXDBString(5, IsUnicode = true)]
[PXDefault(typeof(AccessInfo.baseCuryID))]
[PXUIField(DisplayName = "Currency", ErrorHandling = PXErrorHandling.Never)]
[PXSelector(typeof(Currency.curyID))]
[CuryID]
public virtual String CuryID { get; set; }
For your scenario you would replace InventoryRaw with your custom attribute:
[PXDefault]
[InventoryRaw(IsKey = true, DisplayName = "Inventory ID")]
public virtual String InventoryCD { get; set; }
Custom attribute [CuryID], if key is autogenerated consider adding FieldDefaulting event:
public sealed class CuryIDAttribute : PXEventSubscriberAttribute, IPXFieldUpdatedSubscriber, IPXRowSelectedSubscriber, IPXRowUpdatingSubscriber, IPXRowUpdatedSubscriber, IPXFieldVerifyingSubscriber
{
public void FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
CurrencyInfo info = e.Row as CurrencyInfo;
if (info != null)
{
//reset effective date to document date first
info.SetDefaultEffDate(sender);
try
{
info.defaultCuryRate(sender);
}
catch (PXSetPropertyException ex)
{
sender.RaiseExceptionHandling(_FieldName, e.Row, sender.GetValue(e.Row, _FieldOrdinal), ex);
}
info.CuryPrecision = null;
}
}
public void RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
CurrencyInfo info = e.Row as CurrencyInfo;
if (info != null)
{
bool disabled = info.IsReadOnly == true || (info.CuryID == info.BaseCuryID);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.curyMultDiv>(sender, info, !disabled);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.sampleCuryRate>(sender, info, !disabled);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.sampleRecipRate>(sender, info, !disabled);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.curyRateTypeID>(sender, info, !disabled);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.curyEffDate>(sender, info, !disabled);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.baseCuryID>(sender, info, false);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.displayCuryID>(sender, info, false);
PXUIFieldAttribute.SetEnabled<CurrencyInfo.curyID>(sender, info, true);
}
}
private bool? currencyInfoDirty = null;
public void RowUpdating(PXCache sender, PXRowUpdatingEventArgs e)
{
CurrencyInfo info = e.Row as CurrencyInfo;
if (info != null && info._IsReadOnly == true)
{
e.Cancel = true;
}
else
{
currencyInfoDirty = sender.IsDirty;
}
}
public void RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
CurrencyInfo info = e.Row as CurrencyInfo;
if (info != null)
{
CurrencyInfo old = e.OldRow as CurrencyInfo;
if (old != null && (String.IsNullOrEmpty(info.CuryID) || String.IsNullOrEmpty(info.BaseCuryID)))
{
info.BaseCuryID = old.BaseCuryID;
info.CuryID = old.CuryID;
}
if (currencyInfoDirty == false
&& info.CuryID == old.CuryID
&& info.CuryRateTypeID == old.CuryRateTypeID
&& info.CuryEffDate == old.CuryEffDate
&& info.CuryMultDiv == old.CuryMultDiv
&& info.CuryRate == old.CuryRate)
{
sender.IsDirty = false;
currencyInfoDirty = null;
}
}
}
public void FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
{
CurrencyInfo info = e.Row as CurrencyInfo;
if (info != null)
{
CMSetup CMSetup = info.getCMSetup(sender);
}
}
}
I am getting the following error when trying to delete a customer:
An unhandled exception has occurred in the function 'MoveNext'
I think i need to add this if statement or something similar.
if(Base.BAccount.Cache.GetStatus(CCustomer) != PXEntryStatus.InsertedDeleted || Base.BAccount.Cache.GetStatus(CCustomer) != PXEntryStatus.Deleted)
I found a couple of links with this issue but non that is specific to the customer page.
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
using (var scope = new PXTransactionScope())
{
Customer row = this.Base.BAccount.Current;
if (row.ParentBAccountID == null)
{
CustomerMaint businessAccount = PXGraph.CreateInstance<CustomerMaint>();
PXResultset<Customer> Children = PXSelect<Customer, Where<Customer.parentBAccountID, Equal<Required<Customer.bAccountID>>>>.Select(Base, row.BAccountID);
foreach (Customer item in Children)
{
businessAccount.Clear();
businessAccount.BAccount.Current = PXSelectorAttribute.Select<Customer.bAccountID>(this.Base.BAccount.Cache, item.BAccountID) as Customer;
item.TermsID = row.TermsID;
item.Status = row.Status;
Contact defContact = PXSelect<Contact, Where<Contact.bAccountID, Equal<Required<BAccount.bAccountID>>, And<Contact.contactID, Equal<Required<BAccount.defContactID>>>>>.Select(businessAccount, item.BAccountID, item.DefContactID);
defContact.EMail = this.Base.DefContact.Current.EMail;
businessAccount.DefContact.Update(defContact);
businessAccount.BAccount.Update(item);
businessAccount.Save.PressButton();
}
}
baseMethod();
scope.Complete();
}
}
I am hoping there is a check I can build in or something that can eliminate the MoveNext error when deleting.
Try to use the same pattern as the base CustomerMaint class which uses UpdateChildAccounts and GetChildAccounts methods to modify the child accounts.
protected virtual void Customer_PrintDunningLetters_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
Customer row = (Customer)e.Row;
CheckExcludedFromDunning(cache, row);
UpdateChildAccounts<Customer.printDunningLetters>(cache, row, GetChildAccounts(sharedCreditPolicy: true));
}
protected virtual void Customer_Status_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
Customer row = e.Row as Customer;
if (row == null) return;
if (row.ParentBAccountID == null)
{
Func<Customer, bool> func;
string newValue = GetSharedCreditChildStatus(row.Status, out func);
UpdateChildAccounts<Customer.status>(cache, row, GetChildAccounts(sharedCreditPolicy: true).Where(func), newValue);
}
}
protected virtual void Customer_ConsolidateToParent_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
Customer row = (Customer)e.Row;
if (row == null) return;
if (row.ParentBAccountID == null)
{
IEnumerable<Customer> childs;
string message = PXMessages.LocalizeFormatNoPrefix(Messages.RelatedFieldChangeOnParentWarning,
PXUIFieldAttribute.GetDisplayName<Customer.consolidateToParent>(sender));
if ((childs = GetChildAccounts()).Any() && e.ExternalCall)
{
if (CurrentCustomer.Ask(message, MessageButtons.YesNo) == WebDialogResult.Yes)
{
UpdateChildAccounts<Customer.consolidateToParent>(sender, row, childs);
}
}
row.SharedCreditPolicy &= row.ConsolidateToParent;
}
else if (row.SharedCreditPolicy == true && row.ConsolidateToParent != true && (bool?)e.OldValue == true)
{
sender.SetValueExt<Customer.sharedCreditPolicy>(row, false);
}
}
protected virtual void UpdateChildAccounts<Field>(PXCache cache, Customer parent, IEnumerable<Customer> enumr, object sourceValue = null)
where Field : IBqlField
{
if (PXAccess.FeatureInstalled<FeaturesSet.parentChildAccount>() &&
parent != null &&
parent.ParentBAccountID == null)
{
sourceValue = sourceValue ?? cache.GetValue<Field>(parent);
foreach (Customer child in enumr)
{
if (sourceValue != cache.GetValue<Field>(child))
{
cache.SetValue<Field>(child, sourceValue);
cache.Update(child);
}
}
}
}
protected virtual IEnumerable<Customer> GetChildAccounts(bool sharedCreditPolicy = false, bool consolidateToParent = false, bool consolidateStatements = false)
{
if (PXAccess.FeatureInstalled<FeaturesSet.parentChildAccount>())
{
PXSelectBase<Customer> select = new PXSelect<Customer, Where<Customer.parentBAccountID, Equal<Current<Customer.bAccountID>>>>(this);
if (sharedCreditPolicy)
{
select.WhereAnd<Where<Customer.sharedCreditPolicy, Equal<True>>>();
}
if (consolidateToParent)
{
select.WhereAnd<Where<Customer.consolidateToParent, Equal<True>>>();
}
if (consolidateStatements)
{
select.WhereAnd<Where<Customer.consolidateStatements, Equal<True>>>();
}
return select.Select().RowCast<Customer>();
}
return Enumerable.Empty<Customer>();
}
Otherwise create a new DAC inheriting from Customer to hold the children and create a data view for them in the graph. You can then modify the children in that data view and they will be persisted automatically when user invoke the Save action from UI.
[Serializable]
public partial class OtherCustomer : Customer
{
public new abstract class bAccountID : PX.Data.BQL.BqlInt.Field<bAccountID> { }
}
PXSelect<OtherCustomer, Where< … >> OtherCustomers;
I have created a new APTran field called UsrPOTranAmt. I would like to populate it with the PO Line amount when the user either adds a PO or a PO Line to the invoice. Later I can compare the line transaction amount to the UsrPOTranAmt and determine if the user is paying more that the PO amount.
My initial thought was to detect when the PONbr field (PO Type, PO Number, and PO Line Number fields) was updated and then set the UsrPOTranAmt field to the same value as the CuryLineAmt or Amount field that was updated by the PO or PO Line selection. I have tried to detect the field_updated event with a warning message for PONbr and POLineNbr but neither approach has worked.
public class APInvoiceEntry_Extension : PXGraphExtension<APInvoiceEntry>
{
protected void APTran_PONbr_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (APTran)e.Row;
if (row.PONbr != null)
{
cache.RaiseExceptionHanding<APTran.PONbr>(row, row.PONbr,
new PXSetPropertyException("PO Line Number Changed", PXErrorLevel.Warning));
}
}
}
I do not receive the warning message so I don't expect that I can set the UsrPOTranAmt either with this event.
If you have not changed the default behavior of the Grid column of CommitChanges to True, it will not cause the postback and call the event. Give that a try.
The commitChanges is definitely required on a filed updated event, but here is the solution from ACM:
public class APTranExt : PXCacheExtension<PX.Objects.AP.APTran>
{
#region UsrPOTranAmt
[PXDecimal]
[PXUIField(DisplayName = "POTranAmt", Enabled = false)]
[PXDBScalar(typeof(Search<POLine.curyLineAmt,
Where<POLine.orderType, Equal<APTran.pOOrderType>,
And<POLine.orderNbr, Equal<APTran.pONbr>,
And<POLine.lineNbr, Equal<APTran.pOLineNbr>>>>>))]
public virtual Decimal? UsrPOTranAmt { get; set; }
public abstract class usrPOTranAmt : PX.Data.BQL.BqlDecimal.Field<usrPOTranAmt> { }
#endregion
}
public class APInvoiceEntry_Extension : PXGraphExtension<APInvoiceEntry>
{
#region Event Handlers
protected void APTran_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e, PXRowUpdated InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (APTran)e.Row;
if(row != null && row.POOrderType != null && row.PONbr != null && row.POLineNbr != null)
{
POLine poline = PXSelect<POLine,
Where<POLine.orderType, Equal<Required<POLine.orderType>>,
And<POLine.orderNbr, Equal<Required<POLine.orderNbr>>,
And<POLine.lineNbr, Equal<Required<POLine.lineNbr>>>>>>.Select(Base, row.POOrderType, row.PONbr, row.POLineNbr);
if(poline != null)
{
cache.SetValue(row, "UsrPOTranAmt", poline.CuryLineAmt);
}
}
}
#endregion
}
I have modified portal copy order functionality to carry forward the source order shipping address detail into new order.
I have added a custom field to Portalcartlines DAC to store source order type & order number and while Proceed to Checkout action I am filling the address from the source order.
The address is properly carry forward to new order, but while saving I am getting error.
Error: Inserting 'Shipping Address' record raised at least one error. Please review the errors. Error: 'RevisionID' cannot be empty. Error: 'Country' cannot be empty
I am using the following code
public class PortalCardLinesExtn : PXCacheExtension<SP.Objects.IN.PortalCardLines>
{
#region UsrSourceOrderType
[PXDBString(2)]
//[PXUIField(DisplayName = "SourceOrderType")]
public virtual string UsrSourceOrderType { get; set; }
public abstract class usrSourceOrderType : IBqlField { }
#endregion
#region UsrSourceOrderNbr
[PXDBString(15)]
//[PXUIField(DisplayName = "SourceOrderNbr")]
public virtual string UsrSourceOrderNbr { get; set; }
public abstract class usrSourceOrderNbr : IBqlField { }
#endregion
}
public class InventoryCardMaint_Extension : PXGraphExtension<InventoryCardMaint>
{
public PXAction<PortalCardLine> ProceedToCheckOut;
[PXButton]
[PXUIField(DisplayName = "Proceed to Checkout")]
public IEnumerable proceedToCheckOut(PXAdapter adapter)
{
Base.DocumentDetails.Cache.Persist(PXDBOperation.Update);
Base.DocumentDetails.Cache.Persist(PXDBOperation.Insert);
Base.DocumentDetails.Cache.Persist(PXDBOperation.Delete);
foreach (PXCache value in Base.Caches.Values)
{
value.IsDirty = false;
}
SOOrderEntry sOOrderEntry = PXGraph.CreateInstance<SOOrderEntry>();
SOOrder sOOrder = sOOrderEntry.Document.Cache.CreateInstance() as SOOrder;
sOOrder = sOOrderEntry.Document.Insert();
sOOrderEntry.Document.Cache.SetValueExt<SOOrderExt.isSecondScreen>(sOOrder, 1);
//sOOrderEntry.Document.Cache.SetValueExt<SOOrderExt.overrideShipment>(sOOrder, true);
SOOrderExt extension = PXCache<SOOrder>.GetExtension<SOOrderExt>(sOOrder);
SOShippingContact sOShippingContact = sOOrderEntry.Shipping_Contact.Cache.Current as SOShippingContact;
SOShippingAddress sOShippingAddress = sOOrderEntry.Shipping_Address.Cache.Current as SOShippingAddress;
PortalCardLines prow = Base.DocumentDetails.Current;
if (prow != null)
{
PortalCardLinesExtn extn = Base.DocumentDetails.Cache.GetExtension<PortalCardLinesTSExtn>(prow);
if (!string.IsNullOrEmpty(extn.UsrSourceOrderNbr) && !string.IsNullOrEmpty(extn.UsrSourceOrderType))
{
SOOrder order = PXSelect<SOOrder, Where<SOOrder.orderType, Equal<Required<SOOrder.orderType>>, And<SOOrder.orderNbr, Equal<Required<SOOrder.orderNbr>>>>>.Select(Base, extn.UsrSourceOrderType, extn.UsrSourceOrderNbr);
if (order != null)
{
SOOrderExt sourceextension = PXCache<SOOrder>.GetExtension<SOOrderExt>(order);
sOOrderEntry.Document.Cache.SetValueExt<SOOrderExt.comment>(sOOrder, sourceextension.Comment);
SOShippingContact contact = PXSelect<SOShippingContact, Where<SOShippingContact.contactID, Equal<Required<SOShippingContact.contactID>>>>.Select(Base, order.ShipContactID);
SOShippingAddress address = PXSelect<SOShippingAddress, Where<SOShippingAddress.addressID, Equal<Required<SOShippingAddress.addressID>>>>.Select(Base, order.ShipAddressID);
contact.OverrideContact = true;
address.OverrideAddress = true;
sOShippingAddress.OverrideAddress = true;
sOShippingContact.OverrideContact = true;
if (contact != null)
{
sOShippingContact.FullName = contact.FullName;
sOShippingContact.Attention = contact.Attention;
sOShippingContact.Phone1 = contact.Phone1;
sOShippingContact.Email = contact.Email;
}
if (address != null)
{
sOShippingAddress.AddressLine1 = address.AddressLine1;
sOShippingAddress.AddressLine2 = address.AddressLine2;
sOShippingAddress.AddressLine3 = address.AddressLine3;
sOShippingAddress.City = address.City;
sOShippingAddress.CountryID = address.CountryID;
sOShippingAddress.State = address.State;
sOShippingAddress.PostalCode = address.PostalCode;
}
sOOrderEntry.Shipping_Contact.Cache.Update(sOShippingContact);
sOOrderEntry.Shipping_Address.Cache.Update(sOShippingAddress);
}
}
}
PXRedirectHelper.TryRedirect(sOOrderEntry, PXRedirectHelper.WindowMode.Same);
return adapter.Get();
}
}
I have tried it on customerid field updated event and this solved the issue.
The code is given below
protected void SOOrder_CustomerID_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (SOOrder)e.Row;
if (row == null) return;
SOOrderExt ext = cache.GetExtension<SOOrderExt>(row);
PortalCardLines prow = Base1.DocumentCardDetails.SelectSingle();
if (prow != null)
{
PortalCardLinesTSExtn extn = PXCache<PortalCardLines>.GetExtension<PortalCardLinesTSExtn>(prow);
if (!string.IsNullOrEmpty(extn.UsrSourceOrderNbr) && !string.IsNullOrEmpty(extn.UsrSourceOrderType))
{
//UsrDeliveryNotes
SOOrder order = PXSelect<SOOrder, Where<SOOrder.orderType, Equal<Required<SOOrder.orderType>>, And<SOOrder.orderNbr, Equal<Required<SOOrder.orderNbr>>>>>.Select(Base, extn.UsrSourceOrderType, extn.UsrSourceOrderNbr);
if (order != null )
{
string notes = PXNoteAttribute.GetNote(Base.Document.Cache, order);
ext.Comment = notes;
row.ShipAddressID = order.ShipAddressID;
row.ShipContactID = order.ShipContactID;
}
}
}
}
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);
}