Unable to create Sales Order via API with items from Inactive Vendor - acumatica

When attempting to create a Sales Order via an API call, if the Vendor marked as Default for any item on the order has status Inactive an error is returned with the message: "PX.Data.PXException: The vendor status is 'Inactive'"
However, when creating the Sales Order through the standard Screen there is no issue with ordering items with Inactive Default Vendors.
We want to keep the Vendors marked as Inactive but need to create the Sales Orders for the items like the Screen allows. How can this be done?

I'm assuming the error is coming from SOLine.VendorID from Brendan comment.
Here are the steps to debug that problem and fix it using FieldVerifying event.
Add SOLine.VendorID field on SalesOrder screen:
Reproduce the error in SalesOrder using the field you added:
Check trace error, it indicates the error is coming from a PXRestrictor attribute:
Check VendorID field, it has a PXRestrictor and the VendorIsInStatus error message you receive:
PXRestrictor attribute validation can be cancelled using the FieldVerifying event, add that handler to SalesOrder for SOLine.VendorID:
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
{
protected void SOLine_VendorID_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
{
e.Cancel = true;
}
}
Test SalesOrder again, if it works you can remove the VendorID/VendorName you added to the grid to debug:

From Brendan's comment I went with modifying the PXRestrictor attribute of the SOLine.VendorID to allow Inactive status as well:
public class SOLineExt : PXCacheExtension<PX.Objects.SO.SOLine> {
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXRestrictor(typeof(Where<Vendor.status, IsNull,
Or<Vendor.status, Equal<BAccount.status.active>,
Or<Vendor.status, Equal<BAccount.status.inactive>,
Or<Vendor.status, Equal<BAccount.status.oneTime>>>>>), PX.Objects.AP.Messages.VendorIsInStatus, typeof(Vendor.status))]
public virtual Int32? VendorID { get; set; }
}

Related

Acumatica Warning Message To Only Affect Shipment Screen SO302000

I'm trying to display a warning every time the ShippedQty field is changed to a value < OrigOrderQty on the "Shipment - SO302000" screen, but I only want the code to be active for that specific screen/form.
I added the code below to extend the SOShipmentEntry graph, which accomplishes my original goal, but the issue is that now the code I added is also being used by the "Create Shipment" action in "Sales Orders - SO301000" screen/form.
Create Shipment Action Discussed
namespace PX.Objects.SO
{
public class SOShipmentEntry_Extension : PXGraphExtension<SOShipmentEntry>
{
#region Event Handlers
protected void SOShipLine_ShippedQty_FieldUpdated(PXCache cache,PXFieldUpdatedEventArgs e)
{
var myrow = (SOShipLine)e.Row;
if (myrow == null) return;
if (myrow.ShippedQty >= myrow.OrigOrderQty)
{
}
else
{
throw new PXSetPropertyException("The difference between the shipped-qty and the ordered-qty will be placed on a back-order", PXErrorLevel.Warning);
}
}
#endregion
}
}
While the warning allows the user to save changes to a shipment on the Shipment Screen/form SO302000 (Because the exception is set up as a warning and not an error), I get the following error when I create a shipment using the "Create Shipment" button on the "Sales Orders - SO301000" screen.
Warning works fine for form-mode
Warning becomes error when processed in background by action button
Any ideas to accomplish this? It is my understanding that if I want to make global changes to a field I must make them in the DAC, but if I want to make changes that only affect screens/forms where a graph is used, then I have to make those changes in the graph code itself. I'm guessing the "Create Shipment" action button in the Sales Orders screen is creating an instance of the graph where I added the code, so I'm wondering what are my options here.
Best regards,
-An Acumatica newbie
If you want your event logic to execute only when CreateShipment is invoked from the Shipment screen you can override the other calls to CreateShipment to dynamically remove your event handler.
The event that invokes CreateShipment action from the SalesOrderEntry graph is Action:
public PXAction<SOOrder> action;
[PXUIField(DisplayName = "Actions", MapEnableRights = PXCacheRights.Select)]
[PXButton]
protected virtual IEnumerable Action(PXAdapter adapter,
[PXInt]
[PXIntList(new int[] { 1, 2, 3, 4, 5 }, new string[] { "Create Shipment", "Apply Assignment Rules", "Create Invoice", "Post Invoice to IN", "Create Purchase Order" })]
int? actionID,
[PXDate]
DateTime? shipDate,
[PXSelector(typeof(INSite.siteCD))]
string siteCD,
[SOOperation.List]
string operation,
[PXString()]
string ActionName
)
In that method it creates a SOShipmentEntry graph to create the shipment. You can override Action and remove your handler from that graph instance:
SOShipmentEntry docgraph = PXGraph.CreateInstance<SOShipmentEntry>();
// >> Remove event handler
SOShipmentEntry_Extension docgraphExt = docgraph.GetExtension<SOShipmentEntry_Extension>();
docgraph.FieldUpdated.RemoveHandler<SOShipLine.shippedQuantity>(docgrapExt.SOShipLine_ShippedQty_FieldUpdated);
// << Remove event handler
docgraph.CreateShipment(order, SiteID, filter.ShipDate, adapter.MassProcess, operation, created);
Note that in order to reference SOShipLine_ShippedQty_FieldUpdated method from another graph you'll have to make it public:
public void SOShipLine_ShippedQty_FieldUpdated(PXCache cache,PXFieldUpdatedEventArgs e)
I have described how to do this in that answer too:
Updating custom field is ending into infinite loop
If you want your event logic to execute only when it is modified in the UI or by web service.
You can use the ExternalCall Boolean property of the PXFieldUpdatedEventArgs parameter.
This property value will be true only when the sender field is modified in the UI or by web service.
Usage example:
protected void SOShipLine_ShippedQty_FieldUpdated(PXCache cache,PXFieldUpdatedEventArgs e)
{
// If ShippedQty was updated in the UI or by a web service call
if (e.ExternalCall)
{
// The logic here won't be executed when CreateShipment is invoked
}
}
ExternalCall Property (PXFieldUpdatedEventArgs)
Gets the value specifying whether the new value of the current DAC field has been changed in the UI or through the Web Service API.

Modify items in Opportunity page - Status field

I have been able to modify the dropdown values for other fields in the Opportunity page like Stage and Source, and even the Status field in other pages like Leads
The CROpportunity.Status column is defined as
public abstract class status : PX.Data.IBqlField { }
[PXDBString(1, IsFixed = true)]
[PXUIField(DisplayName = "Status", Visibility = PXUIVisibility.SelectorVisible)]
[PXStringList(new string[0], new string[0])]
[PXMassUpdatableField]
[PXDefault()]
public virtual string Status { get; set; }enter code here
There is no LeadStatuses attribute to be replaced.
In the Contact DAC, the column is defined in the following way
#region Status
public abstract class status : IBqlField { }
[PXDBString(1, IsFixed = true)]
[PXUIField(DisplayName = "Status")]
[LeadStatuses]
public virtual String Status { get; set; }
#endregionenter code here
It is, therefore possible to substitute the LeadStatuses attribute with a CacheExtension for the Contact DAC, or a GraphExtension over LeadMaint. But it's not the case for the CROpportunity DAC or the OpportunityMaint graph.
Any ideas?
Thanks
UPDATE
Following #Philippe suggestion, I was able to rename an existing status. "New" to "Newest"
However, when I try to create a new Automation Step. Reviewing the Combo Box values smartpanel, doesn't show the option to add new values:
Combo box values
I reviewed the AU tables but couldn't find any where these statuses values are stored - it would seem to be handled in the BLC layer
UPDATE 2
The option to add new values can be obtained by right-clicking on the grid
Combo box values
The statuses in Opportunities and Leads are defined in the Automation Steps. I covered a part of how automation steps can define business logic in this StackOverflow answer that could be helpful to you.
The basics here are as follow: Documents can have "workflows/steps" where some actions and fields are only available if they are in a specified step. Those steps are configurable without customization and thus can have status that are manage without customization as well. For more information about Automation Steps, I would refer you to the Help under Help > User Guide > Automation > Overview > Workflow Customization by Means of Automation Steps

Customize Add Stock Item in SO and PO

currently I am doing some customization in "add stock item" of Sales Order and Purchase Order in acumatica, in this customization I added "Marked For" column but it is not editable even though its already there, how can I make it editable for the users?
Attached here is the screenshot of customized "add stock item".
Things done:
Extended SoSiteStatusSelected DAC.
Edited .aspx and added Marked For Column
Add your field to your SOOrderStatusSelected DAC extension. It has to be an unbound field because the DAC is not bound to a table. You can add further logic in event handlers to persist to database.
public class SOSiteStatusSelectedExt : PXCacheExtension<PX.Objects.SO.SOSiteStatusSelected>
{
[PXString]
[PXUIField(DisplayName="Marked For")]
public virtual string UsrMarkedFor { get; set; }
public abstract class usrMarkedFor : IBqlField { }
}
Enable the field in SOOrderEntry graph extension in the RowSelected event:
public class SOOrderEntryExtension : PXGraphExtension<SOOrderEntry>
{
protected virtual void SOSiteStatusSelected_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
PXUIFieldAttribute.SetEnabled<PX.Objects.SO.SOSiteStatusSelectedExt.usrMarkedFor>(sender, e.Row, true);
}
Tested in Acumatica v6.10.0010 for SalesOrder screen:
Digging into SOSiteStatusLookup which is inherited from INSiteStatusLookup you will find that 'OnRowSelected' it is disabling all fields except for 'Selected' and 'QtySelected' columns. To override this, try adding the following to a SOOrderEntry graph extension for any field you want to add to this view as editable from your extension...
protected virtual void SOSiteStatusSelected_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected del)
{
del?.Invoke(sender, e);
PXUIFieldAttribute.SetEnabled<MyExtension.MyField>(sender, e.Row, true);
}
Replace 'MyExtension' with your class extension name and 'MyField' with the mark for field name.

Shipment Email in Automation Notifications

Does anyone has any idea how can I have email from Shipment Settings tab on Shipment Screen (SO302000) on Automation Notifications screen (SM205040) under Emails dropdown/lookup on Addresses tab. Please refer to the below screenshot.
I did not find any code which I customize or if there is any DB table I need to populate. Please suggest.
Here's what you need, create DAC Extension for main DAC of primary view (here Shipment) and declare an unbound user-field depending on out-of-box SOShipment.ShipContactID and decorated with PXSelector.
public class SOShipmentPXExt : PXCacheExtension<SOShipment>
{
public abstract class usrShipContactID : IBqlField { };
[PXInt()]
[PXSelector(typeof(Search<SOShipmentContact.contactID>))]
[PXUIField(DisplayName = "Ship Contact", Enabled = false, Visible = false, IsReadOnly = true)]
[PXDependsOnFields(typeof(SOShipment.shipContactID))]
public int? UsrShipContactID
{
get
{
return Base.ShipContactID;
}
}
}
And add this field on Shipment Entry Page
After publishing above change, you should be able to use this field in Automation Notifications (SM205040)

Adding search function to the AlternateID on the Sales Order Line Grid

I want to add a pxselector to the AlternateID field on the Sales Order Line grid to search multiple alternate id's for a single item for the customer identified on the SOHeader. I added the following code:
namespace PX.Objects.SO {
public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry> {
#region Event Handlers
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXSelector(typeof(Search<INItemXRef.alternateID,
Where<INItemXRef.inventoryID, Equal<Current<SOLine.inventoryID>>,
And<INItemXRef.bAccountID, Equal<Current<SOOrder.customerID>>>>>),
typeof(INItemXRef.alternateID),
typeof(INItemXRef.inventoryID),
typeof(INItemXRef.bAccountID)
)]
public void SOLine_AlternateID_CacheAttributeCacheAttached() {}
#endregion
}
}
I also deleted the text control from the Transactions grid and re-added it as a selector.
My selector shows up on the AlternateID field on as expected but when the selector is clicked the error "Error #107: View doesn't exist" is displayed.
This was an example Ruslan from Acumatica went over with us at Framework training last week in Ohio, but I obviously missed a step. Any help would be appreciated.
George, you put a wrong name for your event handler and that causes the error. Try replacing your handler with the code snippet below:
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXSelector(typeof(Search<INItemXRef.alternateID>),
typeof(INItemXRef.alternateID),
typeof(INItemXRef.inventoryID),
typeof(INItemXRef.bAccountID))]
public void SOLine_AlternateID_CacheAttached(PXCache sender)
{
}

Resources