Update customer children from parent account - acumatica

Page: AR303000 Version:18.203.0006
Good day
I need to update the Child accounts details(Terms, Status, and Email) when the parent account changes. The problem is I do not know how to save the children Customer's contact email field from Customer_RowPersisting.
The customer child accounts do save a, but the Contact details do not.
namespace PX.Objects.AR
{
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
#region Event Handlers
protected void Customer_RowPersisting(PXCache cache, PXRowPersistingEventArgs e)
{
Customer row = (Customer)e.Row;
if (row.ParentBAccountID == null)
{
PXResultset<Customer> Children = PXSelectJoin<Customer,
LeftJoin<BAccount, On<Customer.bAccountID, Equal<BAccount.bAccountID>>>,
Where<BAccount.parentBAccountID, Equal<Required<Customer.bAccountID>>>>.Select(Base, row.BAccountID);
if (Children == null) { return; }
Contact ParContact = PXSelect<Contact, Where<Contact.contactID, Equal<Required<Contact.contactID>>>>.Select(Base, row.DefBillContactID);
foreach (Customer item in Children)
{
//Customer
item.TermsID = row.TermsID;
item.Status = row.Status;
cache.Update(item);
//Contact Details
Contact Cur = PXSelect<Contact, Where<Contact.contactID, Equal<Required<Contact.contactID>>>>.Select(Base, item.DefBillContactID);
Cur.EMail = ParContact.EMail;
cache.Update(Cur);
}
//Do not know if this is right
cache.Persist(PXDBOperation.Normal);
}
}
#endregion
}
}

You can override the Persist() method! You should add a reference for the PX.CS.Contracts.dll dll.
public class CustomerMaintExt : PXGraphExtension<CustomerMaint>
{
#region Overrides
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();
}
}
#endregion
}

Related

APRegisterExt not saving data on APInvoiceEntry

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;
}

Customer Persist Override gives NextMove issue while deleting

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;

Error while copying order in Acumatica portal

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;
}
}
}
}

Customize Navigation (Next/Prev) buttons on Compound Key Management screens

The Item Warehouse Details are composed of a compound key of Inventory ID + Site ID. The navigation buttons on the Manage > Item Warehouse Details screen move between the latter part of the key, the Warehouse.
Would it be possible to customize them to navigate between Inventory IDs instead? What events / methods would allow for that?
In order to customize navigation buttons in Acumatica, you should redeclare some or all navigation buttons in an appropriate BLC extension. Below is an example showing how to implement navigation on the Item Warehouse Details screen only by Inventory ID:
using PX.Data;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace PX.Objects.IN
{
public class INItemSiteMaintExt : PXGraphExtension<INItemSiteMaint>
{
public PXFirstCst<INItemSite> First;
public PXPreviousCst<INItemSite> Previous;
public PXNextCst<INItemSite> Next;
public PXLastCst<INItemSite> Last;
public class PXFirstCst<TNode> : PXFirst<TNode>
where TNode : class, IBqlTable, new()
{
public PXFirstCst(PXGraph graph, string name)
: base(graph, name)
{
}
public PXFirstCst(PXGraph graph, Delegate handler)
: base(graph, handler)
{
}
[PXUIField(DisplayName = ActionsMessages.First, MapEnableRights = PXCacheRights.Select)]
[PXFirstButton]
protected override IEnumerable Handler(PXAdapter adapter)
{
var graph = _Graph as INItemSiteMaint;
if (graph == null) return base.Handler(adapter);
InjectCustomWhereClause(ref adapter, graph, typeof(Where<True, Equal<True>>));
return base.Handler(adapter);
}
}
public class PXPreviousCst<TNode> : PXPrevious<TNode>
where TNode : class, IBqlTable, new()
{
public PXPreviousCst(PXGraph graph, string name)
: base(graph, name)
{
}
public PXPreviousCst(PXGraph graph, Delegate handler)
: base(graph, handler)
{
}
[PXUIField(DisplayName = ActionsMessages.Previous, MapEnableRights = PXCacheRights.Select)]
[PXPreviousButton]
protected override IEnumerable Handler(PXAdapter adapter)
{
var graph = _Graph as INItemSiteMaint;
if (graph == null) return base.Handler(adapter);
InjectCustomWhereClause(ref adapter, graph,
typeof(Where<InventoryItem.inventoryCD, Less<Required<InventoryItem.inventoryCD>>>));
return base.Handler(adapter);
}
protected override void Insert(PXAdapter adapter)
{
adapter.Searches = null;
base.Insert(adapter);
}
}
public class PXNextCst<TNode> : PXNext<TNode>
where TNode : class, IBqlTable, new()
{
public PXNextCst(PXGraph graph, string name)
: base(graph, name)
{
}
public PXNextCst(PXGraph graph, Delegate handler)
: base(graph, handler)
{
}
[PXUIField(DisplayName = ActionsMessages.Next, MapEnableRights = PXCacheRights.Select)]
[PXNextButton]
protected override IEnumerable Handler(PXAdapter adapter)
{
var graph = _Graph as INItemSiteMaint;
if (graph == null) return base.Handler(adapter);
InjectCustomWhereClause(ref adapter, graph,
typeof(Where<InventoryItem.inventoryCD, Greater<Required<InventoryItem.inventoryCD>>>));
return base.Handler(adapter);
}
protected override void Insert(PXAdapter adapter)
{
adapter.Searches = null;
base.Insert(adapter);
}
}
public class PXLastCst<TNode> : PXLast<TNode>
where TNode : class, IBqlTable, new()
{
public PXLastCst(PXGraph graph, string name)
: base(graph, name)
{
}
public PXLastCst(PXGraph graph, Delegate handler)
: base(graph, handler)
{
}
[PXUIField(DisplayName = ActionsMessages.Last, MapEnableRights = PXCacheRights.Select)]
[PXLastButton]
protected override IEnumerable Handler(PXAdapter adapter)
{
var graph = _Graph as INItemSiteMaint;
if (graph == null) return base.Handler(adapter);
InjectCustomWhereClause(ref adapter, graph, typeof(Where<True, Equal<True>>));
return base.Handler(adapter);
}
}
private static void InjectCustomWhereClause(ref PXAdapter adapter, INItemSiteMaint graph,
Type conditionToInjectCommand)
{
var bqlCommand = adapter.View.BqlSelect;
var newCommand = new List<Type>(BqlCommand.Decompose(bqlCommand.GetType()));
var newCommandCopy = new List<Type>(newCommand);
var conditionToReplaceCommand = typeof(Where<INItemSite.inventoryID, Equal<Optional<INItemSite.inventoryID>>>);
var conditionToReplace = new List<Type>(BqlCommand.Decompose(conditionToReplaceCommand).Skip(1));
var conditionToInject = new List<Type>(BqlCommand.Decompose(conditionToInjectCommand).Skip(1));
bool whereClause = false;
for (int i = 0; i < newCommand.Count - 1; i++)
{
whereClause = whereClause || typeof(IBqlWhere).IsAssignableFrom(newCommand[i]);
if (!whereClause) continue;
if (newCommand[i] == conditionToReplace.First())
{
bool found = true;
for (int index = 0; index < conditionToReplace.Count; index++)
{
if (newCommand[i + index] != conditionToReplace[index])
{
found = false;
break;
}
}
if (found)
{
newCommandCopy.RemoveRange(i, conditionToReplace.Count);
newCommandCopy.InsertRange(i, conditionToInject);
break;
}
}
}
var cmd = BqlCommand.CreateInstance(BqlCommand.Compose(newCommandCopy.ToArray()));
var newAdapter = new PXAdapter(new PXView(graph, false, cmd));
PXAdapter.Copy(adapter, newAdapter);
var inventoryState = graph.itemsiterecord.Cache.
GetValueExt<INItemSite.inventoryID>(graph.itemsiterecord.Current) as PXSegmentedState;
if (inventoryState != null && inventoryState.Value != null)
newAdapter.Parameters = new object[] { inventoryState.Value };
else
newAdapter.Parameters = new object[] { string.Empty };
newAdapter.SortColumns = null;
newAdapter.Descendings = null;
adapter = newAdapter;
}
}
}

Populating unbound field from another bound custom field

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.

Resources