I am creating shipment of type Transfer from the custom screen, using below code, shipment is creating successfully but status in Sales Order screen is not updating, and also it is not allowing me to create shipment from Sales Order screen again because it already has an open shipment.
The status is getting updated when I confirm shipment.
soShipmentGraph.CreateShipment(soOrderGraph.Document.Current, graph.Document.Current.SiteID, graph.Document.Current.ShipDate, false, SOOperation.Issue, created);
The status is updated towards the end of the CreateShipment method based on SOOrder.UpdateShipmentCntr field value if no exception were thrown during shipment creation:
if (order.OpenShipmentCntr > 0)
{
order.Status = SOOrderStatus.Shipping;
order.Hold = false;
soorder.Update(order);
}
The OpenShipmentCntr field is updated by the SOShipmentEntry.UpdateShipmentCntr method:
protected virtual void UpdateShipmentCntr(PXCache sender, object Row, short? Counter)
{
SOOrder order = (SOOrder)PXParentAttribute.SelectParent(sender, Row, typeof(SOOrder));
if (order != null)
{
order.ShipmentDeleted = (Counter == -1) ? true : (bool?)null;
order.ShipmentCntr += Counter;
if (((SOOrderShipment)Row).Confirmed == false)
{
order.OpenShipmentCntr += Counter;
}
soorder.Cache.SetStatus(order, PXEntryStatus.Updated);
}
}
When creating the shipment, SOShipmentEntry should insert a SOOrderShipment record that links SOOrder (Sales Order) with SOShipment (Shipment) records. The SOOrderShipment should be visible in the Orders tab of the shipment:
After insertion of the SOOrderShipment record the SOOrderShipment RowInserted event in SOShipmentEntry is raised:
protected virtual void SOOrderShipment_RowInserted(PXCache sender, PXRowInsertedEventArgs e)
{
UpdateShipmentCntr(sender, e.Row, (short)1);
}
I couldn't determine the reason why the status won't change so I'd suggest to debug the steps leading to sales order status change.
Related
I have a graph override for Invoices
public class ARInvoiceEntry_Extension : PXGraphExtension<ARInvoiceEntry>
and in one of the event handlers I am updating TaxZoneID, which works fine. However, the taxes do not get updated or recalculated. I have tried the approach mentioned here
cache.SetValueExt<SOOrder.taxZoneID>(order, branchLoc.VTaxZoneID);
but that doesn't work for me. I have tried it in _FieldUpdating, _FieldUpdated, and even ARInvoice_RowPersisting(PXCache cache, PXRowPersistingEventArgs e, PXRowPersisting InvokeBaseHandler) events. Any ideas on why it doesn't work? The TaxZone and rates are already in the database (we are not using Avatax).
--- edit 1 ---
Here is the code where TaxZoneID is updated
namespace PX.Objects.AR
{
public class ARInvoiceEntry_Extension : PXGraphExtension<ARInvoiceEntry>
{
#region Event Handlers
protected void ARShippingAddress_PostalCode_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e, PXFieldUpdated del)
{
// PXTrace.WriteInformation("ARShippingAddress_PostalCode_FieldUpdated");
ARShippingAddress row = e.Row as ARShippingAddress;
if (row != null) {
if (DoChangeTaxZone(row)) {
var invoice = Base.Document.Current;
if (invoice != null) {
invoice.TaxZoneID = GetTaxZoneId(row);
sender.SetValueExt<ARInvoice.taxZoneID>(invoice, invoice.TaxZoneID);
}
}
}
if (del != null)
{
del(sender, e);
}
}
#endregion
private bool DoChangeTaxZone(ARShippingAddress row)
{
// logic ...
return true;
}
private string GetTaxZoneId(ARShippingAddress row)
{
// logic ...
return "TAX-ZONE-ID";
}
}
}
When you programmatically interact with tax records using the typical methods, the tax total will not refresh properly. The Tax DAC attribute doesn't recalculate the totals by default to improve performance.
To force tax attribute refresh you need to change the tax calc mode.
Tax calc mode NoCalc does not recalculate totals. This is the default mode.
Setting tax calc mode to ManualCalc is necessary to refresh the updated tax.
Code example to update the tax amount field, you can adapt it to update tax zone.
ARInvoiceEntry invoiceMaint = PXGraph.CreateInstance<ARInvoiceEntry>();
TX.TaxAttribute.SetTaxCalc<ARTran.taxCategoryID>(invoiceMaint.Transaction.Cache, null, TX.TaxCalc.ManualCalc);
invoiceMaint.CurrentDocument.Current = invoiceMaint.Document.Search<ARInvoice.refNbr>("AR005452", ARDocType.Invoice).FirstOrDefault();
invoiceMaint.Taxes.Select();
invoiceMaint.Taxes.Current = invoiceMaint.Taxes.Search<ARTaxTran.taxID>("CAGST").FirstOrDefault();
invoiceMaint.Taxes.Cache.SetValueExt<ARTaxTran.curyTaxAmt>(invoiceMaint.Taxes.Current, 3);
invoiceMaint.Taxes.Update(invoiceMaint.Taxes.Current);
invoiceMaint.SelectTimeStamp();
invoiceMaint.Save.Press();
when we are creating the Shipment “Is-Component” field we added newly in Sales Order Screen when we checked this field and when we process the shipment in Shipment screen the particular inventory data item is not passing only for checked ” Is component “item , unchecked items of “Is component” item are able to pass to shipment screen .
[PXOverride]
public IEnumerable Action(PXAdapter adapter, Nullable<Int32> actionID, Nullable<DateTime> shipDate, String siteCD, String operation, String ActionName, ActionDelegate baseMethod)
{
if (actionID == 1)
{
SOShipmentEntry ShipGraph = PXGraph.CreateInstance<SOShipmentEntry>();
PXGraph.InstanceCreated.AddHandler<SOShipmentEntry>((graph) =>
{
ShipGraph.RowInserting.AddHandler<SOShipLine>((sender, e) =>
{
foreach (SOLine line in Base.Transactions.Select())
{
ShipGraph.Transactions.Current = PXSelect<SOShipLine, Where<SOShipLine.shipmentNbr, Equal<Required<SOShipLine.shipmentNbr>>>>.Select(Base, line.InventoryID, line.OrderNbr);
SOShipLine ShipLine = new SOShipLine();
SOLineExt NonStklnExt = line.GetExtension<SOLineExt>();
if (ShipGraph.Transactions.Current == null)
{
//if (NonStklnExt.UsrIsComponent == true || NonStklnExt.UsrIsComponent == false || NonStklnExt.UsrInvFlag == true || NonStklnExt.UsrInvFlag == false || NonStklnExt.UsrStkInventoryID == null || NonStklnExt.UsrStkInventoryID != null)
//{
ShipLine.InventoryID = line.InventoryID;
ShipLine.TranDesc = line.TranDesc;
// }
ShipGraph.Transactions.Insert(ShipLine);
}
}
Base.Transactions.View.RequestRefresh();
});
});
}
return baseMethod(adapter, actionID, shipDate, siteCD, operation, ActionName);
}
I can assume that these items are added based on the flag, not always added based on the item. If that is the case, I would check the Require Shipment flag on the Non-Stock item to have it automatically added.
I would go at this by overriding the SOShipmentEntry CreateShipment function, rather than the SOShipLine Insert handler. Ensure you override the one that has the QuickProcessFlow.
From there, I would search for the initial order and order lines as you are doing after the shipment is created. Your logic is checking if the flags are checked or unchecked on the line, and should be updated. For example, if you wanted to find all items that are not on the shipment that have the component checked that are not auto added based on the NonStockShip flag, I would go at it like this:
public delegate void CreateShipmentDelegate(SOOrder order, Nullable<Int32> SiteID, Nullable<DateTime> ShipDate, Nullable<Boolean> useOptimalShipDate, String operation, DocumentList<SOShipment> list, ActionFlow quickProcessFlow);
[PXOverride]
public void CreateShipment(SOOrder order, Nullable<Int32> SiteID, Nullable<DateTime> ShipDate, Nullable<Boolean> useOptimalShipDate, String operation, DocumentList<SOShipment> list, ActionFlow quickProcessFlow, CreateShipmentDelegate baseMethod)
{
baseMethod(order, SiteID, ShipDate, useOptimalShipDate, operation, list, quickProcessFlow);
if (order == null)
return; //do not process for shipments that did not have an order sent for some reason
//get all lines for non-stockitems that are not flagged to be shipped that have the component checked
var SalesOrderLines = PXSelectJoin<
SOLine,
InnerJoin<InventoryItem,
On<SOLine.inventoryID, Equal<InventoryItem.inventoryID>>>,
Where<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>,
And<SOLine.orderType, Equal<Required<SOLine.orderType>>,
And<InventoryItem.nonStockShip, Equal<False>,
And<InventoryItem.stkItem, Equal<False>,
And<SOLineExt.usrIsComponent, Equal<True>>>>>>>
.Select(Base, order.OrderNbr, order.OrderType);
foreach(SOLine SalesOrderLine in SalesOrderLines)
{
//double check that they were not added.... and match the orig line nbr
var ShipmentLinesForItem = PXSelect<
SOShipLine,
Where<SOShipLine.shipmentNbr, Equal<Current<SOShipment.shipmentNbr>>,
And<SOShipLine.shipmentType, Equal<Current<SOShipment.shipmentType>>,
And<SOShipLine.inventoryID, Equal<Required<SOShipLine.inventoryID>>,
And<SOShipLine.origLineNbr, Equal<Required<SOShipLine.origLineNbr>>>>>>>
.Select(Base, SalesOrderLine.InventoryID, SalesOrderLine.LineNbr);
if (ShipmentLinesForItem.Count == 0)
{
//create your shipment lines for these items
SOShipLine ShipmentLine = new SOShipLine();
//set fields required. See function SOOrderEntry.CreateShipmentFromSchedules for examples of fields that should be set.
Base.Transactions.Insert(ShipmentLine);
}
}
}
We have a test DAC called UsrNonRelatedScanField with two fields : OrderNbr and ScanStatus.
Here's our simple query to grab the correct ordernbr and assign it to a SOOrderExt field:
NonRelatedScanField lastScan = PXSelect<NonRelatedScanField,
Where<NonRelatedScanField.orderNbr,
Equal<Required<SOOrder.orderNbr>>>>.Select(Base, row.OrderNbr);
if(lastScan != null)
{
rowExt.UsrNonRelatedScanField = lastScan.ScanStatus;
}
This logic is held in a SOOrder_RowSelecting() method.
Full Method implementation:
protected virtual void SOOrder_RowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
SOOrder row = (SOOrder)e.Row;
if (row == null) return;
SOOrderExt rowExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(row);
NonRelatedScanField lastScan = PXSelect<NonRelatedScanField,
Where<NonRelatedScanField.orderNbr,
Equal<Required<SOOrder.orderNbr>>>>.Select(Base, row.OrderNbr);
if (lastScan != null)
{
rowExt.UsrNonRelatedScanField = lastScan.ScanStatus;
}
}
Expected Results : Get the current Orders scan status from lastScan DAC
Actual Results: Will populate correctly only on the initial order opened. When selecting other orders the old value is persisting unless I manually refresh the page. When manually refreshed the correct data comes in.
I haven't had any issues in the past with BQL queries, this specific query is not behaving as expected.
Thank you
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: