Calculating Dates with Acumatica - acumatica

Trying to calculate a date by simply adding two(2) days from another field. The code below does not work because it says DateAdd does not exist in the current context. When you try to add anything, it says that DataTime fields cannot use opperand like +
Here is the code that is failing:
protected void PMProject_UsrClearPanelsOrdered_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (PMProject)e.Row;
if (cache.GetValue(row, "UsrClearPanelsOrdered") != null)
{
DateTime estimated = (DateTime)cache.GetValue(row, "UsrClearPanelsOrdered");
cache.SetValue<ContractExt.usrStuccoDateUpdate>(row, DateAdd(estimated, 'd', 2));
}
}

Related

Copying a value to SOLines after updating the header is not persisiting

I have a user field in the sales order header. When a user types their amount into that header, it loops through the lines and sets another user field based on that header. However, those lines are not saving their values. They are updated on the screen, but I am not sure they are updated in the cache. However, if I click on a line in the details window first, then update the value in the header, that line saves just fine and the others do not.
protected virtual void SOOrder_UsrMarkupPercent_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
SOOrder order = e.Row as SOOrder;
if (order == null || (order.LastModifiedByScreenID == "CR304000" && order.OrderNbr.Trim().ToLower().Contains("<new>"))) return;
SOOrderExt orderExt = order.GetExtension<SOOrderExt>();
SetMarkupPercentAllLines(cache, orderExt.UsrMarkupPercent);
}
public void SetMarkupPercentAllLines(PXCache cache, decimal? percent)
{
foreach (SOLine line in Base.Transactions.Select())
{
SOLineExt lineExt = line.GetExtension<SOLineExt>();
lineExt.UsrMarkupPercent = percent;
//cache.SetValue<SOLineExt.usrMarkupPercent>(line, percent);
}
}
I tried just doing lineExt.UsrMarkupPercent = percent as well as cache.SetValue(line, percent) and cache.SetValueExt(line, percent) and nothing seems to work. I've tried using a PXSelect rather than Base.Transactions.Select() as well, but that didn't make a different. Is this not updating the cache properly do to something I am not doing?
I appreciate any help. Thanks!
you need to update the value in cache (Ex: Base.Transactions.Update(line)) after setting the value in the extension field.
Something like this:
foreach (SOLine line in Base.Transactions.Select())
{
SOLineExt lineExt = line.GetExtension<SOLineExt>();
lineExt.UsrMarkupPercent = percent;
Base.Transactions.Update(line);
}
Usually you will need to call the cache Update or cache.SetValueExt. In your commented line you had the cache of SOOrder and not Base.Transactions.Cache.SetValueExt. Using the view.Update in your case should work fine

Sales Price Updating Every Other Time

I have extended the SOOrderEntry graph and added the following code in order to update another line on the same sales order that is related to the current line that is being updated:
protected virtual void SOLine_RowUpdating(PXCache cache, PXRowUpdatingEventArgs e)
{
if (e.NewRow == null)
{
return;
}
SOLine soLine = (SOLine)e.NewRow;
SOLine relatedLine = Base.Transactions.Search<SOLine.inventoryID>
(456);
if (relatedLine != null)
{
relatedLine.Qty = soLine.Qty;
relatedLine.CuryUnitPrice = 24.20;
Base.Transactions.Update(relatedLine);
Base.Transactions.View.RequestRefresh();
}
}
When I try to test this by updating the Qty on the current line, the Unit Price on the related line only updates every other time that I update the Qty. The related item is a Non-stock item where the current item is a Stock Item.
I'm doing this in a Sales Demo environment on 18.102.0048
I tried this but, now the Extended Price is always 0.00:
protected virtual void SOLine_RowUpdating(PXCache cache, PXRowUpdatingEventArgs e)
{
if (e.NewRow == null)
{
return;
}
SOLine soLine = (SOLine)e.NewRow;
SOLine relatedLine = Base.Transactions.Search<SOLine.inventoryID>
(456);
if (relatedLine != null)
{
SOLine oldRelatedLine = PXCache<SOLine>.CreateCopy(relatedLine);
relatedLine.Qty = soLine.Qty;
relatedLine.CuryUnitPrice = 24.20;
Base.Transactions.Cache.RaiseRowUpdated(relatedLine, oldRelatedLine);
Base.Transactions.Update(relatedLine);
Base.Transactions.View.RequestRefresh();
}
}
When a field calculated value depends on another field value it's sometimes required to trigger events for the value to be recalculated.
In some cases it only requires firing the event for the field that you modified. Assigning values using the C# assignment operator (=) or the SetValue method will not trigger the events handler, SetValueExt method will:
// Doesn't trigger events
relatedLine.Qty = soLine.Qty;
cache.SetValue<SOLine.qty>(relatedLine, soLine.Qty);
// This will trigger events
cache.SetValueExt<SOLine.qty>(relatedLine, soLine.Qty);
There are some cases where you need to fire events for the whole row too. You can use the RaiseXxxYyy methods to do that. I used Current in the example but you might have to adapt it if Current is not the row being modified:
SOLine oldRowCopy = PXCache<SOLine>.CreateCopy(Base.Transactions.Current);
Base.Transactions.Current.Qty = soLine.Qty;
Base.Transactions.Cache.RaiseRowUpdated(Base.Transactions.Current, oldRowCopy);
EDIT:
Looking at updated question, it might not make much of a difference but I suggest you switch the order of these 2 lines:
Base.Transactions.Cache.RaiseRowUpdated(relatedLine, oldRelatedLine);
Base.Transactions.Update(relatedLine);
Like this:
// You want the value in Cache to be updated
Base.Transactions.Update(relatedLine);
// After Cache value is set you want to raise the events
Base.Transactions.Cache.RaiseRowUpdated(relatedLine, oldRelatedLine);
Thanks to HB_ACUMATICA, here's the code that resolved this:
protected virtual void SOLine_RowUpdating(PXCache cache, PXRowUpdatingEventArgs e)
{
if (e.NewRow == null)
{
return;
}
SOLine soLine = (SOLine)e.NewRow;
SOLine relatedLine = Base.Transactions.Search<SOLine.inventoryID>(456);
if (relatedLine != null)
{
SOLine oldRelatedLine = PXCache<SOLine>.CreateCopy(relatedLine);
relatedLine.Qty = soLine.Qty;
relatedLine.CuryUnitPrice = 24.20;
object outPrice = 0.01;
outPrice = (relatedLine.CuryUnitPrice * relatedLine.Qty);
cache.SetValueExt<SOLine.curyExtPrice>(relatedLine, outPrice);
Base.Transactions.Cache.RaiseRowUpdated(relatedLine, oldRelatedLine);
Base.Transactions.Update(relatedLine);
Base.Transactions.View.RequestRefresh();
}
}

FGetting a Form Field from a grid extension

I have added a field to the Prepare Replenishment form that needs to be updated when a user selects a row in the Replenishment Item grid. How do I access the field. I know it is in the INReplenishmentFilterExt but I can't figure out how to get access to the extension.
Edit #1: I am able to get the value of the field but it does not update on the screen when I use cache.SetValue. I am trying to update this filter extension field from inside of the Selected event handler.
protected void INReplenishmentItem_Selected_FieldUpdating(PXCache cache, PXFieldUpdatingEventArgs e)
{
var row = (INReplenishmentItem)e.Row;
if (row == null)
return;
INReplenishmentFilter filter = Base.Filter.Current;
INReplenishmentFilterExt filterExt = PXCache<INReplenishmentFilter>.GetExtension<INReplenishmentFilterExt>(filter);
decimal poAmount = filterExt.UsrPOAmount.HasValue ? filterExt.UsrPOAmount.Value : 0;
decimal lastPrice = pvi.LastPrice.HasValue ? pvi.LastPrice.Value : 0;
decimal newPOAmount = poAmount + lastPrice;
cache.SetValue<INReplenishmentFilterExt.usrPOAmount>(filterExt, newPOAmount);
}
You cannot set the value of the Filter using the Cache of INReplenishmentItem.
I have edited my answer, the code below should work.
//Always use virtual methods for Event Handlers
protected virtual void INReplenishmentItem_Selected_FieldUpdating(PXCache sender, PXFieldUpdatingEventArgs e)
{
//Try not to use vars. Especially when you know the Type of the object
INReplenishmentItem row = e.Row as INReplenishmentItem;
if (row != null)
{
INReplenishmentFilter filter = Base.Filter.Current;
INReplenishmentFilterExt filterExt = PXCache<INReplenishmentFilter>.GetExtension<INReplenishmentFilterExt>(filter);
decimal poAmount = filterExt.UsrPOAmount ?? 0;
decimal lastPrice = pvi.LastPrice ?? 0;//Not sure what pvi is
decimal newPOAmount = poAmount + lastPrice;
//"sender" is the cache that specifically stores the datatype of row
//Therefor you cannot use it to update records of a different datatype
//You also should not pass an Extension into the argument that should be the row object you are trying to update
Base.Filter.Cache.SetValueExt<INReplenishmentFilterExt.usrPOAmount>(filter, newPOAmount);
}
}

How to pass line item custom field value to sales order from opportunity?

I have a custom line number field in opportunity product tab for customer to re-sequence the selected products and the grid is sorted on custom field value.
I am trying to pass the value from opportunity to sales order which also having a similar field.
the following code i have tried and it did not work
PXGraph.InstanceCreated.AddHandler<SOOrderEntry>((graph) =>
{
graph.RowUpdated.AddHandler<SOLine>((cache, args) =>
{
CROpportunityProducts product = (adapter.View.Graph as OpportunityMaint).Products.Current;
CROpportunityProductsExtNV productext = PXCache<CROpportunityProducts>.GetExtension<CROpportunityProductsExtNV>(product);
SOLine soline = (SOLine)args.Row;
SOLineExtNV solineext = PXCache<SOLine>.GetExtension<SOLineExtNV>(soline);
solineext.UsrLineNo = productext.UsrLineNo;
});
});
The following piece of code returns same value for all line numbers
You can implement RowInserting Event handler as below:
graph.RowInserting.AddHandler<SOLine>((cache, args) =>
{
var soLine = (SOLine)args.Row;
CROpportunityProducts opProduct = PXResult<CROpportunityProducts>.Current;
SOLineExtNV soLineExt = PXCache<SOLine>.GetExtension<SOLineExtNV>(soLine);
CROpportunityProductsExtNV opProductExt = PXCache<CROpportunityProducts>.GetExtension<CROpportunityProductsExtNV>(opProduct);
soLineExt.UsrLineNo = opProductExt.UsrLineNo;
});
wish they could split up the call to create the order and the call to insert the lines to make it easier to customize. We have done something similar. Here is a sample from what I tested using a graph extension and overriding the DoCreateSalesOrder call in the opportunitymaint graph. (This assumes the select on products is the same order the transaction on the sales order were inserted. I am sure there could be a better answer, but this is an example I have handy.)
public class CROpportunityMaintExtNV : PXGraphExtension<OpportunityMaint>
{
[PXOverride]
public virtual void DoCreateSalesOrder(Action del)
{
try
{
del();
}
catch (PXRedirectRequiredException redirect)
{
var products = this.Products.Select().ToArray();
int rowCntr = 0;
foreach (SOLine soLine in ((SOOrderEntry)redirect.Graph).Transactions.Select())
{
// Assumes inserted rows in same order as products listed (default should be the key)
//Current product
CROpportunityProducts currentProduct = products[rowCntr];
var productExtension = currentProduct.GetExtension<CROpportunityProductsExtNV>();
((SOOrderEntry) redirect.Graph).Transactions.Cache.SetValueExt<SOLineExtNV.usrLineNo>(soLine, productExtension.UsrLineNo);
rowCntr++;
}
throw redirect;
}
}
}
The problem you had with your code is the Current product was always the same which resulted in the same value.

Change String length or decimal precision of field attribute dynamically

I'm trying to use setup data from one table to allow me to format fields on the fly / dynamically. I know I can change field names and visibility based on the PXUIFieldAttribute class, but changing the precision or string length is a bit trickier, obviously. From the research I've done, I've come up with the following example code that seems like it should work - but I get the error:
"Unable to cast object of type 'PX.Data.PXUIFieldAttribute' to type 'PX.Data.PXDBDecimalAttribute'.
I don't see why this is occurring...
protected virtual void xTACOpenSourceDetail_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
var osd = (PXCache)sender;
foreach (PXDBDecimalAttribute attribute in this.Caches<xTACOpenSourceDetail>().GetAttributes("Number1"))
{
PXDBDecimalAttribute someAttribute = attribute as PXDBDecimalAttribute;
if (someAttribute != null)
{
someAttribute.DBProperties._precision = 4;
}
}
}
I just tried the below code in sales order screen and it seems working!
var props = typeof(SOOrder).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(PXDecimalAttribute)));
foreach (System.Reflection.PropertyInfo item in props)
{
PXDecimalAttribute.SetPrecision(this.Base.Caches[typeof(SOOrder)], item.Name, 1);
}
You might need to change this to match your DAC.

Resources