Skip to main content
Solved

Prevent Sales Order 'Copy Order' Action from Copying Certain Fields


Hello,

I have created some custom validation fields that are specific to an order. When I conducted my testing, it brings these fields over. I figured out how to disable the native ‘Copy/Paste’ functionality, lots of good information here from the community on that, however, sales orders have one other option- ‘Copy Order’ action. I have tried field defaulting, field updating, and row inserted  event handlers. None of them trigger to nullify my target fields. I have looked through the source code and tried to attach to the IsCopyOrder attribute, which I think would work- but I don’t think any of the events are firing.. any help would be great. One of the ways I have tried doing it below- it prevents the Copy/Paste perfectly, but no luck with the IsCopyOrder side of it.

        protected void SOOrder_UsrBlyReviewedBy_FieldUpdating(PXCache cache, PXFieldUpdatingEventArgs e)
{
if (e.Row is null) return;
var row = (SOOrder)e.Row;

if (Base.IsCopyPasteContext || Base.IsCopyOrder)
{
e.NewValue = null;
}
}

I have tried FieldDefaulting, as that is presenting itself a lot in these forum posts and what is used in the native logic of the Copy Order action, but unfortunately, that isn’t having the same effect for me.. not sure if there is something I might be missing in the field setups? Field setup below:

        #region UsrBlyReviewedBy
BPXDBGuid]
dPXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
)PXSelector(typeof(Search<Users.pKID>),
SubstituteKey = typeof(Users.username))]
)PXUIField(DisplayName = "Reviewed By", Enabled = false)]
public virtual Guid? UsrBlyReviewedBy { get; set; }
public abstract class usrBlyReviewedBy : PX.Data.BQL.BqlGuid.Field<usrBlyReviewedBy> { }
#endregion

Any help would be greatly appreciated!

Hello,

 

I think Copy Order is a specific action, so the only way I can think of to modify its behavior is to PXOverride] it. Here is an example in a discussion about overriding: Override method in child extention | Community (acumatica.com)

I’m not that familiar with the Copy Order action. You should be able to invoke the original method and then add your own code. In the worst-case scenario you may need to copy all the original action and add your logic in the specific part where you need it, the downside is that this forces you to keep updating it every time the original method changes (when upgrading versions).

 


Hey @Marco Villasenor- thanks for the input! Unfortunately, that is exactly what I am trying to avoid.. that CopyOrder action is like 600 lines long so I don’t think it’s a good idea to override and rewrite. In the source code, they have a boolean IsCopyOrder that they set and if its true then certain logic fires- it then gets put back after the order has been successfully copied- see below:

		public PXAction<SOOrder> copyOrder;
rPXButton(CommitChanges = true, IgnoresArchiveDisabling = true), PXUIField(DisplayName = "Copy Order", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
public virtual IEnumerable CopyOrder(PXAdapter adapter)
{
List<SOOrder> list = adapter.Get<SOOrder>().ToList();
WebDialogResult dialogResult = copyparamfilter.AskExt(setStateFilter, true);
if ((dialogResult == WebDialogResult.OK || (this.IsContractBasedAPI && dialogResult == WebDialogResult.Yes)) && string.IsNullOrEmpty(copyparamfilter.Current.OrderType) == false)
{
this.Save.Press();
SOOrder order = PXCache<SOOrder>.CreateCopy(Document.Current);

IsCopyOrder = true;
try
{
using (IsArchiveContext == true ? new PXReadThroughArchivedScope() : null)
this.CopyOrderProc(order, copyparamfilter.Current);
}
finally
{
IsCopyOrder = false;
}

List<SOOrder> rs = new List<SOOrder> { Document.Current };
return rs;
}
return list;
}

I then look at the fields that are utilizing this flag:

		protected virtual void CurrencyInfo_CuryID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
if (PXAccess.FeatureInstalled<FeaturesSet.multicurrency>())
{
if (e.Row != null && IsCopyOrder)
{
e.NewValue = ((CurrencyInfo)e.Row).CuryID ?? customer?.Current?.CuryID;
e.Cancel = true;
}
else
{
if (customer.Current != null && !string.IsNullOrEmpty(customer.Current.CuryID))
{
e.NewValue = customer.Current.CuryID;
e.Cancel = true;
}
}


}
}

This is great, however, when I try it myself on my custom fields, it doesn’t work.

I think I am going to move forward with a workaround which is to disable the action if these fields are filled out and require them to use copy and paste and then copy order. I’m not happy with it, but I don’t have much more time to spend on this.


Hi @rhooper91 ,

Have you tried something like   PXCopyPasteHiddenFields] or oPXCopyPasteHiddenView] attributes to preventing to copy this custom field?
hope, it helps!


Hey @Dipak Nilkanth- I have seen this and have not tried. The reason being is that I believe this only works for Copy/Paste functionality, right? As Marco pointed out, this is an action on the sales order with Acumatica logic associated with it.. so I wouldn’t imagine it would respect this attribute.. unless you think it would? I can give a shot. If I were to go that direction, I believe the same problem exists from a maintenance perspective and that is in order to introduce this to the view, you have to redefine the entire view in the graph extension and then maintain it going forward- is this correct?


Yes, you are right. I'm also not sure and haven't tried this. I thought it might help if none of the above solutions work.


Just to confirm @rhooper91, is your FieldUpdating event triggering and are you seeing the flag values? or is it not triggering?


@Dipak Nilkanth - Thank you!

@Marco Villasenor- That is a good question- I just set the condition to always true to set the value to null- went into an order that has the value filled in- pressed ‘Copy Order’ and it set the value and ignored the logic I added. Based on that test, it looks like it just isn’t firing. What would be the next option from an event perspective?


...I don’t think it’s a good idea to override and rewrite

Agreed, don’t rewrite. But what about overriding and extending to blank out your fields. There’s no downsides to that that I can think of.

 

Here’s how I did it in the past, for what it’s worth. Can’t vouch for the methodology:

protected virtual void _(Events.RowInserting<SOOrder> e)
{
SOOrder row = e.Row;
if (row is null) return;

// Clears UDFs when using the 'Copy Order' action
e.Cache.SetValueExt(row, "AttributeRNASENT", null);
}

 


Hey @darylbowman- how would I go about doing that? Would I need to catch the newly created order redirect and set the fields to null? From my experience- you can lead with some code or end with some code- just not entirely sure how to implement the logic appropriately.


Something like this?

public delegate IEnumerable CopyOrderDelegate(PXAdapter adapter)
[PXOverride]
public virtual IEnumerable CopyOrder(PXAdapter adapter, CopyOrderDelegate baseMethod)
{
var result = baseMethod(adapter);

// Reset fields
Base.Document.SetValueExt<SOOrderExt.usrBlyReviewedBy>(Base.Document.Current, null);
Base.Document.Update(Base.Document.Current);

return result;
}

 


Hey @darylbowman- let me give this a shot and I will let you know. At first glance, I feel like the adapter is the source order, so wouldn’t it just make the source order fields null? Please correct me if my train of thought is going off the rails lol.

I will try this and I will also try doing a try/catch- and catch the redirect and then try setting the values of that to null.. I have had success on that in the past.


I think I found the issue. The FieldUpdating event is not triggering for your fields because the action is not modifying your fields directly, they are just being copied to the new order by the CreateCopy method. But the action does perform an update once it finishes setting all the fields around line 1572 of the SOOrderEntry graph.
Try putting your code in a RowUpdating event with the same condition for Base.IsCopyOrder and set all your custom fields to null there. This event should be firing correctly.


...wouldn’t it just make the source order fields null? 

This process is somewhat unusual in that it is copying the original Order to a new Order in the same graph. If you ran your code before the original method, I believe .Current would be the original Order. Run after the original method, I believe it should be the new Order.


@Marco Villasenor - I tried doing this, see code below. Unfortunately, no luck. Thank you so much for diligence on this topic!

protected void SOOrder_RowUpdating(PXCache cache, PXRowUpdatingEventArgs e)
{
if (e.Row is null) return;
var row = (SOOrder)e.Row;

if (Base.IsCopyOrder)
{
Base.Document.SetValueExt<SOOrderExt2.usrBlyReviewedBy>(row, null);
Base.Document.Update(row);
}
}

@darylbowman - This worked. I was definitely overthinking the override method when I should have just went for it. This is the final code.

public delegate IEnumerable CopyOrderDelegate(PXAdapter adapter);
PXOverride]
public virtual IEnumerable CopyOrder(PXAdapter adapter, CopyOrderDelegate baseMethod)
{
var result = baseMethod(adapter);

// Reset fields
Base.Document.SetValueExt<SOOrderExt2.usrBlyReviewedBy>(Base.Document.Current, null);
Base.Document.Update(Base.Document.Current);

return result;
}

Thank you both!
 


Reply