We have a simple customization that makes the Customer Order field required. But we do not know how to prevent the requirement on Transfer-type orders, which hides the Customer Order field. I found a similar article (Make Salesperson ID a Required field on SOLine) that discusses excluding a requirement for a "line" field, but I think this scenario (preventing requirement of Customer Order field for Transfer Sales orders) might be even simpler. Thanks for any help.
Change PXDefaultAttribute/PXUIFieldAttribute based on your business rules in SOOrder RowSelected event handler of SOOrderEntry graph extension:
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
{
protected void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
SOOrder soOrder = e.Row as SOOrder;
if (soOrder != null)
{
bool isRequired = (soOrder.OrderType != SOOrderTypeConstants.TransferOrder);
PXDefaultAttribute.SetPersistingCheck<SOOrder.customerOrderNbr>(sender,
soOrder,
isRequired ? PXPersistingCheck.NullOrBlank : PXPersistingCheck.Nothing);
PXUIFieldAttribute.SetRequired<SOOrder.customerOrderNbr>(sender, isRequired);
}
}
}
Related
I have a similar type of issue as in
Acumatica refer custom field to another custom field on different screen
except that I am using custom source fields.
I created and added 2 fields to the SO Line to capture EDI data needed for invoicing. I created 2 new fields on the invoice line with the same name (different data class of course) on the SO Invoice form. Below is the code for 1 field on each of the forms:
SO301000 (Sales Orders):
[PXDBString(3)]
[PXUIField(DisplayName="Cust.Invoice Line Nbr.")]
[PXFormula(typeof(Selector<SOLineExt.usrCInvLine, ARTranExt.usrCInvLine>))]
SO303000 (Invoices):
[PXDBString(3)]
[PXUIField(DisplayName="Cust.Invoice Line Nbr.")]
It compiles but the data is not being copied to the invoice when created from shipment. I also added 1 of the fields to the shipment form for testing purposes but it does nit capture that value either.
Do I have this backwards?
After reviewing it into more details, you could override the Prepare Invoice method on SOOrderEntry graph (and also anywhere else is needed).
By overriding the PrepareInvoice Method of SOOrderEntry graph you could add a Handler(RowInserting) to SOInvoiceEntry graph to populate your new Custom field with the value on SOOrder.
See sample below where I'm doing similar action copying value from SOOrder(Header) to ARTran(details).
You can use this sample to achieve your goal: (In your case you could use ARInvoice instead of ARTran)
SOOrderEntry:
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> prepareInvoice;
[PXUIField(DisplayName = "Prepare Invoice", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Visible = false)]
[PXButton]
public virtual IEnumerable PrepareInvoice(PXAdapter adapter)
{
PXGraph.InstanceCreated.AddHandler<SOInvoiceEntry>((graph) =>
{
graph.RowInserting.AddHandler<ARTran>((sender, e) =>
{
//Custom logic goes here
var row = (ARTran)e.Row;
if (row == null)
return;
SOOrder order = Base.Document.Current;
if (order != null)
{
var tranExt = PXCache<ARTran>.GetExtension<ARTranExt>(row);
//Below to be change to your needs
//Here you can look for the SOLine of the SOOrder instead
var orderExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(order);
if (orderExt != null && tranExt != null)
{
tranExt.UsrContactID = orderExt.UsrContactID;
}
//END
}
});
});
return Base.prepareInvoice.Press(adapter);
}
}
You could also find more information and instructions provided by my colleague on the stackoverflow link below:
Acumatica custom field SOLine transferred to ARTran
I have a modification in the sales order needs to update the sales order line unit price with a derived value. This is working well and the new unit price shows up after the item has been selected and my code in the SOLine_RowUpdating event has executed. However after the quantity is selected the SOLine_RowUpdating executes again and after that the system calculates discounts like it normally would. Since I have my own price that should not be discounted I'd like to over-ride or cancel this standard discount calculation and just leave my price as is. Here is the SOLine_RowUpdating code and this is working well.
protected virtual void SOLine_RowUpdating(PXCache sender, PXRowUpdatingEventArgs e)
{
if (e.NewRow == null) {return; }
Customer customer = Base.customer.Current;
if (customer == null) return;
SOLine soLine = (SOLine)e.NewRow;
int BAAccountID = Convert.ToInt32(customer.BAccountID);
int lCompanyID = PX.Data.Update.PXInstanceHelper.CurrentCompany;
int lInventoryID = Convert.ToInt32(soLine.InventoryID);
LookupPriceAndDiscountDetails(BAAccountID, lCompanyID, lInventoryID); // My own code
sender.SetValueExt<SOLine.curyUnitPrice>(soLine, gdNewUnitPrice); //New price is in gdNewUnitPrice
Base.Transactions.Cache.RaiseRowUpdated(soLine, soLine);
Base.Transactions.View.RequestRefresh();
}
After lots of investigation I found this method suggested by various posts that is supposed to clear out / cancel discounts and in fact I can find it in the standard PX.Objects.SO.SOOrderEntry Row_Updated event but when I try it in my graph extension it does not update or clear out in that the soline (cache) values still show the discount numbers. I must be missing something simple.
Any ideas appreciated at this point...
protected void SOLine_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
SOLine row = e.Row as SOLine;
DiscountEngine<SOLine>.ClearDiscount(sender,row);
// RecalculateDiscounts(sender, row); // ? (Maybe this)
}
You are on right track. Just few more comments.
1. Acumatica will always execute basic SOLine_RowUpdated event and then will execute your's SOLine_RowUpdated
2. If you want to control execution flow of SOLine_RowUpdated events, you can do something like this:
protected void SOLine_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e, PXRowUpdated del)
{
//some code
//del or pointer to basic method can be called like this:
del(cache, e);
}
del will be pointer to method SOLine_RowUpdated
You'll have following options:
a. Don't call del at all ( I don't recommend you this approach because basic method has plenty of staff in it, not just discount calculation)
b. call del and then remove discount information
c. In case if your method ClearDiscount will not clear discount information, then it can be because it's tries to achieve it via simple assign, maybe you can try instead SetValueExt method.
One more point to keep in mind. By default Acumatica will call basic RowUpdated method and then it will call your method, so you don't need to use delegate. I'd recommend you to start from SetValueExt in your RowUpdated graph extension instead of simple assignment.
To make it easier you could just turn off the call to RecalculateDiscounts using the following graph extension:
public class SOOrderEntryExtension : PXGraphExtension<SOOrderEntry>
{
[PXOverride]
public virtual void RecalculateDiscounts(PXCache sender, SOLine line, Action<PXCache, SOLine> del)
{
// if no discounts wanted, just return
// else call the base/standard Acumatica calc discounts on sales order...
if (del != null)
{
del(sender, line);
}
}
}
You can also write your own pricing logic by using a graph extension on ARSalesPriceMaint:
public class ARSalesPriceMaintExtension : PXGraphExtension<ARSalesPriceMaint>
{
[PXOverride]
public virtual decimal? CalculateSalesPriceInt(PXCache sender, string custPriceClass, int? customerID, int? inventoryID, int? siteID, CurrencyInfo currencyinfo, decimal? quantity, string UOM, DateTime date, bool alwaysFromBaseCurrency,
Func<PXCache, string, int?, int?, int?, CurrencyInfo, decimal?, string, DateTime, bool, decimal?> del)
{
//run your custom price logic here and return
// or return the base/standard Acumatica price logic...
return del?.Invoke(sender, custPriceClass, customerID, inventoryID, siteID, currencyinfo, quantity, UOM, date, alwaysFromBaseCurrency);
}
}
This way you do not need to fight the events, but override the calls the events are using to set Discounts and Price on the sales order. I also believe ARSalesPRiceMaint extension will override other screens using the pricing logic which helps to reduce duplicate code on different order entry screens.
In Sales Order screen, I'm trying to enable the CustomerOrderNbr field if the status is completed
protected void SOOrder_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
SOOrder doc = e.Row as SOOrder;
if (doc == null)
{
return;
}
if (doc.Completed == true )
{
PXUIFieldAttribute.SetEnabled(cache, doc , true);
PXUIFieldAttribute.SetEnabled<SOOrder.customerOrderNbr>(cache, doc, true);
}
}
however, it remains disabled and not doing what it's supposed to do. So what am I doing wrong ? Am I on the right event to override at all ?
Or is the screen really locked in once the Sales Order is Completed ?
Thanks for any answers.
Since Sales Orders screen is heavily driven by Automation Steps, in addition to extended RowSelected handler for the SOOrder DAC, it's an absolute must to modify automation steps for Completed orders that disable entire SOOrder :
In addition to the automation step change shown above, you should keep SOOrder_RowSelected handler:
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
SOOrder order = e.Row as SOOrder;
if (order == null) return;
if (order.Completed == true)
{
PXUIFieldAttribute.SetEnabled<SOOrder.customerOrderNbr>(sender, order, true);
}
}
}
With those 2 changes in place, Customer Order will stay enabled for SO Orders with Completed status:
I have custom code on the Sales Order form that prevents editing SOLine descriptions unless it's a specific SOLine Code. I see that my custom code is being reached, but it seems that something else is overriding my logic, enabling editing on the field after I disable it. I was wondering if there are pre-defined automations that might be doing this for the Sales Order screen, or if there is some other place I should be looking to prevent this behavior.
//I had debug code that validated that RowSelected and SetEnabled were begin called
public class SOOrderEntry_Extension:PXGraphExtension
{
#region Event Handlers
protected void SOLine_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (SOLine)e.Row;
if(row != null && row.InventoryID.HasValue) {
//Only allow editing of parts description if the partno is 'NOTE'
InventoryItem inventoryItem = PXSelect<InventoryItem, Where<InventoryItem.inventoryID, Equal<Required<InventoryItem.inventoryID>>>>.Select(this.Base, row.InventoryID);
if(inventoryItem.InventoryCD == "NOTE") {
PXUIFieldAttribute.SetEnabled<SOLine.tranDesc>(cache, row, true);
} else {
PXUIFieldAttribute.SetEnabled<SOLine.tranDesc>(cache, row, false);
}
}
}
}
Unfortunately, your RowSelected handler will make no effect on the Line Description column because of how automation steps are configured for the Sales Orders screen:
In order to keep Line Description open for editing, you should change a number of Automation Steps disabling the entire Document Details grid on Sales Orders and subscribe to RowSelected handler for the SOOrder DAC to allow editing on the cache level for the SOOrder and SOLine DACs. Below are the changes required to enable Line Description for completed sales orders (if necessary, similar changes should be made to other Automation steps defined for the Sales Orders screen):
Subscribe to SOOrder_RowSelected handler to allow editing on the cache level for the SOOrder and SOLine DACs:
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
SOOrder order = e.Row as SOOrder;
if (order != null && order.Status == SOOrderStatus.Completed)
{
sender.AllowUpdate = true;
Base.Transactions.Cache.AllowUpdate = true;
}
}
}
Modify Sales Orders' SO Completed automation step to open Line Description for editing. In addition to enabled Line Description, it's necessary to enable at least one of the SOOrder fields, otherwise the Save button will never become enabled for completed sales orders:
I have a custom field on my SOOrder called "UsrProcessTypes," my goal is to have a pop up dialog when users choose this specific option "STCK." I tried the .Ask on a row selected on the base.documentcurrent on a row selected function and it was working correctly(testing purposes). When I applied it to the fieldverifying it was unsuccessful.
protected virtual void SOOrder_UsrProcessTypes_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
{
SOOrder row = (SOOrder)e.Row;
SOOrderExt rowExt = sender.GetExtension<SOOrderExt>(row);
if(rowExt.UsrProcessTypes == "STCK")
{
if (Base.CurrentDocument.Ask("CONFIRM RECALCULTION",
"Confirm Recalculation",
MessageButtons.OK) != WebDialogResult.OK)
{
//
}
}
Thanks in advance
Fixed the issue, I needed to use a rowupdating event instead of field verifying to achieve my goal.