I was wondering if anyone knew of a way to prevent certain fields from updating with default/stored data when updating the Customer field on the Sales Order page under a certain condition.
My Goal: When on the Sales Order page, if a certain Order Type is selected (in this case, the order type that signifies it is a Sales Order created and sent from our website), changing the Customer Field does not update/overwrite the Financial Settings or the Shipping Settings. This is because the Financial and Shipping settings fields are populated and sent from the website, and may have more specific information than the stored Customer information.
I want to keep the loading of default data for other tabs/fields, but keep the customer-entered billing and shipping info.
The SOOrder_CustomerID_FieldUpdated event on the sales order graph updates all related customer information based on the change of customer id. You can override it in a graph extension. The contact and address information is used as an ID to another table so all you need to do is keep the same contact or address ID. I tested the following graph extension and it seems to work by keeping the ID values before calling the base method.
public class SOOrderEntryMyExtension : PXGraphExtension<SOOrderEntry>
{
protected virtual void SOOrder_CustomerID_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated del)
{
var order = (SOOrder)e.Row;
var oldCustomerID = (int?)e.OldValue;
var orderBeforeBase = (SOOrder)cache.CreateCopy(order);
del?.Invoke(cache, e);
if (order == null || orderBeforeBase == null || oldCustomerID == null || order.CustomerID == oldCustomerID || order.OrderType != "WO")
{
return;
}
if (order.BillAddressID != orderBeforeBase.BillAddressID)
{
cache.SetValueExt<SOOrder.billAddressID>(order, orderBeforeBase.BillAddressID);
}
if (order.BillContactID != orderBeforeBase.BillContactID)
{
cache.SetValueExt<SOOrder.billContactID>(order, orderBeforeBase.BillContactID);
}
if (order.ShipAddressID != orderBeforeBase.ShipAddressID)
{
cache.SetValueExt<SOOrder.shipAddressID>(order, orderBeforeBase.ShipAddressID);
}
if (order.ShipContactID != orderBeforeBase.ShipContactID)
{
cache.SetValueExt<SOOrder.shipContactID>(order, orderBeforeBase.ShipContactID);
}
}
}
Related
I need to attach custom data into new fields added to INTranCost when the PO Receipt occurs.
Following the breadcrumbs, it seems that POReceiptEntry -> Release Action eventually calls INDocumentRelease.ReleaseDoc that eventually creates INTranCost. I tried extending both POReceiptEntry and INDocumentRelease to add an event for INTranCost_RowInserted to publish a PXTrace message, but the trace doesn't appear, telling me that I'm not hitting the event that I expected. (Which explains why the real business logic I need included didn't fire.)
protected virtual void _(Events.RowInserted<INTranCost> e)
{
PXTrace.WriteInformation("This is it!");
}
Of course, I want to put real code in this spot, but I am just trying to make sure I'm hitting the event properly. This works on pretty much everything else I've done, including attaching similar data to INTranExt fields. I cannot get it to work for INTranCost so that I can add to INTranCostExt. At this point, I can't determine if it is location (which graph extension) or a special methodology required for this special case.
I also tried overriding events and putting a breakpoint on the code, but it's like I'm not even on the same process. (Yes, I checked that I am connected to the right Acumatica instance and that I have no errors.)
What event in which graph is required to capture the creation in INTranCost for a PO Receipt to update custom fields in INTranCostExt?
Using Request Profiler, I was able to determine that I was close but not deep enough. While the INTranCost object to insert was built in INDocumentRelease FILE, the actual insert was processed in INReleaseProcess graph in that same file.
I only need to execute this "push" from the data captured on the POLine when the INTranCost record is created, and LineNbr is a key field and therefore never updated after it is set. I need to be sure that I have enough data to make the connection back, and the primary key links me back to the INTran easily. That subsequently gets back to the POReceiptLine to the POLine where the data is maintained that needs the "current value" to be captured when the transaction is posted. Since I need to update the DAC Extension, I need to use an event that will allow an existing DAC.Update to apply my values. Therefore, I added an event handler on INTranCost_LineNbr_FieldUpdated since that value should not be "updated" after it is set initially.
Code that accomplished the task:
public class INReleaseProcess_Extension : PXGraphExtension<INReleaseProcess>
{
public override void Initialize()
{
base.Initialize();
}
protected virtual void _(Events.FieldUpdated<INTranCost.lineNbr> e)
{
INTranCost row = (INTranCost) e.Row;
INTran tran = PXSelect<INTran,
Where<INTran.docType, Equal<Required<INTran.docType>>,
And<INTran.refNbr, Equal<Required<INTran.refNbr>>,
And<INTran.lineNbr, Equal<Required<INTran.lineNbr>>
>>>>
.SelectSingleBound(Base, null, row.DocType, row.RefNbr, (int?) e.NewValue);
if (tran?.POReceiptType != null && tran?.POReceiptNbr != null)
{
PXResultset<POReceiptLine> Results = PXSelectJoin<POReceiptLine,
InnerJoin<POLine, On<POLine.orderType, Equal<POReceiptLine.pOType>,
And<POLine.orderNbr, Equal<POReceiptLine.pONbr>,
And<POLine.lineNbr, Equal<POReceiptLine.pOLineNbr>>>>,
InnerJoin<POOrder, On<POOrder.orderType, Equal<POLine.orderType>,
And<POOrder.orderNbr, Equal<POLine.orderNbr>>>>>,
Where<POReceiptLine.receiptType, Equal<Required<POReceiptLine.receiptType>>,
And<POReceiptLine.receiptNbr, Equal<Required<POReceiptLine.receiptNbr>>,
And<POReceiptLine.lineNbr, Equal<Required<POReceiptLine.lineNbr>>>>>>.
SelectSingleBound(Base, null, tran.POReceiptType, tran.POReceiptNbr, tran.POReceiptLineNbr);
if (Results != null)
{
foreach (PXResult<POReceiptLine, POLine, POOrder> result in Results)
{
POReceiptLine receipt = result;
POLine line = result;
POOrder order = result;
POLineExt pOLineExt = PXCache<POLine>.GetExtension<POLineExt>(line);
INTranCostExt iNTranCostExt = PXCache<INTranCost>.GetExtension<INTranCostExt>(row);
if (pOLineExt != null && iNTranCostExt != null)
{
Base.Caches[typeof(INTranCost)].SetValueExt<INTranCostExt.usrField>(row, pOLineExt.UsrField);
}
}
}
}
}
}
We have exposed CustomerID and Customer Location for TR order type, as standard Acumatica will not expose these fields. We have another custom screen which will be created before we create a shipment, so our custom screen will store these customer and customer location details for another purpose.
We are unable to create a shipment with the customer of type customer and vendor, it is allowing to create shipment only with company type customer. This is working in 2017R2 but not in 2019R1.
Here is the error message:
An error occurred during processing of the field Customer value C000000001 AR Error: Incorrect value specified. Specify a customer (for shipments of the Shipment type) or a company business account (for shipments of the Transfer type).
Sample code to make fields visible for TR Order Type also. I am trying this is fresh Acumatica instance with Sales data and without customizations published.
protected void SOOrder_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (SOOrder)e.Row;
if (row.OrderType == "TR")
{
PXUIFieldAttribute.SetVisible<SOOrder.customerID>(cache, (object)row, true);
PXUIFieldAttribute.SetVisible<SOOrder.customerLocationID>(cache, (object)row, true);
}
}
I have a checkbox on a DAC extension to the BAccount that I want to use to set a checkbox on Case when a customer is selected. Here is what the checkbox looks like on the Business Account screen.
Here is the field on the Case screen that I want to set when the customer is selected.
I found a stack overflow question where a couple of custom fields on a customer screen were to be copied to custom fields on a sales order. I have tried to substitute my fields into the code but I haven't been able to make it work.
Here is what I have tried. I'm not sure what I am missing.
protected void CRCase_CustomerID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
var crcase = e.Row as CRCase;
if (crcase.CustomerID != null)
{
var customer = PXSelectorAttribute.Select<CRCase.customerID>(sender, crcase) as BAccountR;
if (customer != null)
{
var customerExt = customer.GetExtension<BAccountExt>();
var crcaseExt = crcase.GetExtension<CRCaseExt>();
crcaseExt.UsrContractCustomer = customerExt.UsrSage100;
}
}
}
I do not understand why BAccountR is used instead of just BAccount. Neither works right now.
I solved the issue by combining are response I received on an earlier post. I modified the last two line as follows:
var customerExt = customer.GetExtension<BAccountExt>();
//var crcaseExt = crcase.GetExtension<CRCaseExt>();
//crcaseExt.UsrContractCustomer = customerExt.UsrSage100;
sender.SetValueExt<CRCaseExt.usrContractCustomer>(crcase, customerExt.UsrSage100 != null);
So here is the final issue that I need to resolve. The checkbox I used on the Business Account screen opens a new tab that displays custom fields. These custom fields are an extension of the BAccount DAC called DSDSage100. It is similar to the extension of the BAccount called Customer. In the DSDSage100 extension there is a field called UsrContractCustomer. That is the field that I want to read and set the Case field to the same value. Here is what the Sage 100 Tab looks like. I have a using directive for my project but I can't find the right reference to the DSDSage100 extension.
var customerExt = customer.GetExtension<DSDSage100>();
sender.SetValueExt<CRCaseExt.usrContractCustomer>(crcase, customerExt.UsrContractCustomer != null);
Acumatica provided the answer. While I "extended the BAccount DAC" with my custom table (DSDSage100, similar to the way Customer is an extension of the BAccount DAC), it is it's own DAC. The solution was:
DSDSage100 mydac = PXSelect<DSDSage100, Where<DSDSage100.bAccountID, Equal<Required<DSDSage100.bAccountID>>>>.Select(Base, crcase.CustomerID);
sender.SetValueExt<CRCaseExt.usrContractCustomer>(crcase, mydac.UsrContractCustomer != null);
Thanks for the help and support.
Client has an Customised field called “Approval Type” on the Purchase Order Entry screen (screenshot attached). By Default this field is available when user creates an Order.
We are implementing the Approval Workflow for this client. The client wants that when a new PO is created, this field should be disabled. But once the PO is approved and user wants to make any change in the approved PO, On selecting “Hold” checkbox option, this field should be active and user should then be allowed to set any value from the field list and save the Order. I tried the Automation steps but could not figure out how to achieve it.
Many Thanks
In the rowselected event of the POOrder, add your conditions and use the PXUIFieldAttribute.SetVisible to hide/show your field.
It will be something like below.
protected virtual void POOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected del)
{
if (e.Row == null) return;
if (del != null) del(sender, e);
PXUIFieldAttribute.SetVisible<YOUR custom FIELD>(sender, e.Row, <Your true condition to show>);
}
We Have Contact Entities in contact Entitie one lookup filed company Name in that lookup having two values 1.Account and 2.Contact . When we are selecting contact show the address filed when we select account hide the address filed we needs to write the plugin to Execute that works. Kindly any one help me on the same.
Thanks!!
Rajesh Singh
First, if you need to make change on a form, you can't use plug-ins. Plug-ins are made for bussinees logics, like Update another record when the first one is created, make complex logic, etc...
What you need it is a javascript that executes on the OnLoad of the form and OnChange event in that OptionSet.
The lines you are looking for are:
function ShowField()
{
// The field is present on the form so we can access to its methods
var optionSet = Xrm.Page.getAttribute("custom_attribute");
if (optionSet == undefined)
{
return;
}
// The control is present on the form so we can access to its methods
var controlAddress = Xrm.Page.getControl("custom_address");
if (controlAddress == undefined)
{
return;
}
var valueOptionSet = optionSet.getValue(); // This is the value you set creating the OptionSet
switch (valueOptionSet)
{
case 0: // Your account value, show
controlAddress.setVisible(true);
case 1: // Your contact value, hide
controlAddress.setVisible(false);
default:
return;
}
}
You need to register a web resource and register the event, if you need more information about the code or why this stuff is here and why this not just tell me.