Set Field Value during Email Sales Order process under Slaes Order Entry Actions - acumatica

I created a new field, UsrAcknowledged, boolean, checkbox, and placed it on the SOLine details grid. I want every line on the details grid to be checked when the Email Sales Order/Quote process is run under Actions for SOOrder. My code is as follows under the SOOrderEntry_Extension:PXGraphExtension
public CRActivityList<SOOrder> Activity;
public PXAction<SOOrder> notification;
[PXUIField(DisplayName = "Notifications", Visible = false)]
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntryF)]
protected virtual IEnumerable Notification(PXAdapter adapter,
[PXString]
string notificationCD
)
{
foreach (SOOrder order in adapter.Get<SOOrder>())
{
var parameters = new Dictionary<string, string>();
parameters["SOOrder.OrderType"] = order.OrderType;
parameters["SOOrder.OrderNbr"] = order.OrderNbr;
Activity.SendNotification(ARNotificationSource.Customer, notificationCD, order.BranchID, parameters);
//order.OrderDesc = "Desc";
foreach (SOLine line in PXSelect<SOLine>.Select(Base, order.OrderNbr))
{
SOLineExt rowExt = line.GetExtension<SOLineExt>();
rowExt.UsrAcknowledged = true;
line.OrderQty = 5;
}
yield return order;
}
}
//order.Desc = "Desc" was an initial simple test just to see if my code was achieving the desired results and the proder desciption was changed as planned.
My code compiles and the email process runs as planned with a green check for successful, but neither the Acknowledged check box nor the Order Quantity are changed. I don't really care about the ord qty, it was just another test.
Any suggestions for what I can change to update the Acknowledged checkbox to checked during the Email Sales Order/Quote under Actions on the SO Order Entry screen would be appreciated

I would say you need to call Base.Transactions.Update(line) after you update your row values inside your foreach.

Related

Why is my hyperlink / button in the grid to launch a screen disabled?

I have a customization to the Sales Orders screen, where I've added a user field (non-bound / [PXString] to hold the value of a PO Receipt Nbr. I populate it with the RowSelected event, and I'm trying to launch the Purchase Receipts screen from that field with a PXAction tied to that field's Linked Command:
The Field:
public abstract class usrPOReceiptNbr : BqlString.Field<usrPOReceiptNbr> { }
[PXString(15, IsUnicode = true)]
[PXUIField(DisplayName = "PO Receipt Nbr", Enabled = true)]
public virtual string UsrPOReceiptNbr { get; set; }
The RowSelected event code to populate the field:
var soordershipment = e.Row as SOOrderShipment;
using (new PXConnectionScope())
{
//get the extension
var soordershipmentext = PXCache<SOOrderShipment>.GetExtension<SOOrderShipmentExt>(soordershipment);
//Get the soorder cache...
SOOrder soorder = Base.Document.Current;
if (soorder != null)
{
//Now get the POReceiptLine record:
PXResultset<POReceiptLine> res = PXSelectJoin<POReceiptLine,
InnerJoin<SOOrder,
On<SOOrder.orderNbr, Equal<POReceiptLine.sOOrderNbr>,
And<SOOrder.orderType, Equal<POReceiptLine.sOOrderType>>>>,
Where<SOOrder.orderNbr, Equal<Required<SOOrder.orderNbr>>>,
OrderBy<Desc<POReceiptLine.receiptNbr>>>.Select(Base, soorder.OrderNbr);
foreach (PXResult<POReceiptLine> rec in res)
{
POReceiptLine porl = (POReceiptLine)rec;
soordershipmentext.UsrPOReceiptNbr = porl.ReceiptNbr;
break; //Stop after the first record, since I only want the highest sorted field
}
}
}
The code to launch the Purchase Receipts screen is as follows:
public PXAction<SOOrder> LaunchPurchaseReceipts;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Launch Purchase Receipts", Enabled = true)]
protected virtual IEnumerable launchPurchaseReceipts(PXAdapter adapter)
{
var soorder = (SOOrder)Base.Document.Current;
POReceiptEntry graph = PXGraph.CreateInstance<POReceiptEntry>();
var soordershipment = (SOOrderShipment)Base.shipmentlist.Current;
var soordershipmentext = PXCache<SOOrderShipment>.GetExtension<SOOrderShipmentExt>(soordershipment);
graph.Document.Current = graph.Document.Search<POReceipt.receiptNbr, POReceipt.receiptType>(soordershipmentext.UsrPOReceiptNbr, soordershipment.ShipmentType);
throw new PXRedirectRequiredException(graph, "Purchase Receipts")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
The problem is that I continue to get this error when launching the hyperlink on the PO Receipt Nbr field for that screen (it never even gets to the code to launch the screen):
...and here's the error...
I've tried forcing the field to enabled with the RowSelected event, using:
PXUIFieldAttribute.SetEnabled<SOOrderShipmentExt.usrPOReceiptNbr>(e.Cache, null, true);
But that doesn't do anything.
Any ideas?
This issue has been resolved with a suggestion from Brendan (thanks much) by using the RowSelected event to set the method's enabled property to true:
LaunchPurchaseReceipts.SetEnabled(true);

Acumatica - Copy custom field contents from SO to IN

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

How can I set a custom field on Acumatica Production Detail Operation when the Production Order is first created?

I have a custom field on an Acumatica Production Detail Operation (UsrEligibleForRoboticFulfillment) that I have created an Action to set based on criteria on the component items in the Materials tab. (code below)
I would like to call this Action to set the field as soon as the Production Order is created, but the split nature of the Production Order is such that there are no events on the Production Detail raised that I can attach to and call the Action. I've tried Row Inserted as well as Persist delegate on the Production Detail graph.
I CAN attach to either the AMProdItem Row Inserted or Persist Delegate on the Production Maint graph, but at this point in time the Operations and Materials have not yet been created.
What's the best way to update this field when a new Production Order is created?
Action code:
public PXAction<AMProdItem> UpdateEligibleForRoboticFulfillment;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Update Robotic Eligibility", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
protected void updateEligibleForRoboticFulfillment()
{
AMProdItem prodDetail = Base.ProdItemRecords.Current;
AMProdOper prodOper = Base.ProdOperRecords.Current;
InventoryItem finishedProduct = PXSelect<InventoryItem,
Where<InventoryItem.inventoryID, Equal<Current<AMProdItem.inventoryID>>>>.Select(Base).FirstOrDefault();
//Only production orders are eligible for robotic fulfillment, not disassemblies
if (prodDetail.OrderType == "MO")
{
bool wasRoboticsEligible = (prodOper.GetExtension<AMProdOperExt>().UsrEligibleForRoboticFulfillment ?? false);
//Get the current branchID
int branchID = (int)Base.Accessinfo.BranchID;
//Get the default site/warehouse for this branch.
INSite site = INTranHelper.GetDefaultSiteForItemBranch(branchID);
//Get the flag indicating whether this site is active for robotics
bool activeRobotics = site.GetExtension<INSiteExt>().UsrActiveRobotics ?? false;
//Get the flags for manual process and component robotics compatible
bool requiresManualProcess = finishedProduct.GetExtension<InventoryItemExt>().UsrManualFinishRequired ?? false;
//Gotta be prepared for the possibility that more than one component is used
//Check for any components that are NOT robotics eligible that have qty required and haven't already been fully allocated
PXResultset<AMProdMatl> components = PXSelectJoin<AMProdMatl,
InnerJoin<InventoryItem, On<InventoryItem.inventoryID, Equal<AMProdMatl.inventoryID>,
And<InventoryItemExt.usrRoboticsCompatible, Equal<False>,
And<AMProdMatl.orderType, Equal<Current<AMProdOper.orderType>>,
And<AMProdMatl.prodOrdID, Equal<Current<AMProdOper.prodOrdID>>,
And<AMProdMatl.operationID, Equal<Current<AMProdOper.operationID>>,
And<AMProdMatl.qtyActual, Less<AMProdMatl.totalQtyRequired>,
And<AMProdMatl.qtyReq, Greater<decimal0>>>>>>>>>>
.Select(Base);
bool roboticsEligible = !requiresManualProcess && activeRobotics;
//If any component is not eligible, the whole operation is not eligible
if (components.Count > 0)
{
roboticsEligible = false;
}
//If the robotics eligible flag should have changed, change it
if (wasRoboticsEligible != roboticsEligible)
{
prodOper.GetExtension<AMProdOperExt>().UsrEligibleForRoboticFulfillment = roboticsEligible;
Base.ProdOperRecords.Update(prodOper);
}
}
}
Had to open a ticket with Acumatica; got a working solution! I had to enclose the persist delegate method in a transaction scope.
Override Persist() method of graph
Call base method first so that Operations and Materials on the Production Order Detail gets created
Enclosed in transaction scope
Something like this:
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
if (/**/)
{
using (var ts = new PXTransactionScope())
{
//Call base method to persist
baseMethod();
/*Custom Logic here*/
ts.Complete();
}
}
else
baseMethod();
}

Creating purchase order with the information from sales order

I'm creating a purchase order based on a sales order via code.
But how to obtain the document details of sales order and copy it to the new purchase order?
Additional Info:
I had created a simple PO in SOOrderEntry BLC. And I also wanna copy the item info(eg:Branch,Inventory ID, Unit Price and so on) in the document details of SO, to the new PO.
Below is the my code, and could you help me?
namespace PX.Objects.SO {
public class SOOrderEntry_Extension: PXGraphExtension < SOOrderEntry > {
#region Event Handlers
public PXAction < PX.Objects.SO.SOOrder > CreatePO;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "CreatePO")]
protected void createPO() {
var graph = PXGraph.CreateInstance<POOrderEntry>();
var order = graph.Document.Insert(new POOrder());
order.OrderType = "Normal"
order.OrderDesc = "Some description";
order.VendorID = 101;
graph.Document.Update(order);
graph.Actions.PressSave();
}
#endregion
}
}

Loading popup value to InventoryID field

with code from Load value from popup to InventoryID field question am able to set the InventoyID from popup to the InventoryID field but the default behavior of Acumatica is missing, like after InventoryID is set from poup, am selecting Item Class then a pop up is firing and asking for confirmation, generally this happen only when we update Item Class for already created Item.
[PXButton]
[PXUIField(DisplayName = "Generate")]
public IEnumerable GenerateInv(PXAdapter adapter)
{
string inventoryCD = "ACUMATICA";
InventoryItem item = PXCache<InventoryItem>.CreateCopy(Base.Item.Current);
OrderedDictionary keys = new OrderedDictionary(StringComparer.OrdinalIgnoreCase)
{
{
typeof(InventoryItem.inventoryCD).Name,
adapter.View.Cache.GetValue(adapter.View.Cache.Current,
typeof(InventoryItem.inventoryCD).Name)
}
};
OrderedDictionary vals = new OrderedDictionary(StringComparer.OrdinalIgnoreCase)
{
{
typeof(InventoryItem.inventoryCD).Name, inventoryCD
}
};
adapter.View.Cache.Update(keys, vals);
if (adapter.Searches != null && adapter.Searches.Length > 0)
{
adapter.Searches[0] = inventoryCD;
}
return adapter.Get();
}
You can try to skip the message window by overriding the Field Verifying on the stock item page for InventoryItem.ItemClassID. You should use some condition to indicate you are running your customer process so the standard message will appear for normal use on the stock items page.
public virtual void InventoryItem_ItemClassID_FieldVerifying(PXCache cache, PXFieldVerifyingEventArgs e, PXFieldVerifying del)
{
try
{
del?.Invoke(cache, e);
}
catch (PXDialogRequiredException)
{
var someSkipMessageWindowCondition = true;
if (someSkipMessageWindowCondition)
{
return;
}
throw;
}
}
Because of the use of the private property doResetDefaultsOnItemClassChange in the Base graph, the process will function as if the message box was answered YES to default the field values from the new item class. If you do not want the values to change using the new class you will need to cancel the field defaultings for the fields found in InventoryItem_ItemClassID_FieldUpdated in the Base graph. This will point out which fields are being updated when doResetDefaultsOnItemClassChange == true.
A better answer to your question would be automatically answering NO which I am unsure how to do. Would be nice to know how do perform that function if someone else knows how to make that call.

Resources