Loading popup value to InventoryID field - acumatica

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.

Related

Acumatica Customize Process Shipments Add branch field from PO Receipts

I'm trying to figure out if it's possible to add fields to the grid on the Process Shipments screen for PO Receipts when the "Prepare Drop-Ship Invoice" action is selected. Specifically, I want to add the POReceipts.BranchID field.
I've studied the source code, and I see where different select commands are run based on the selected action, but I don't understand what drives the grid to show the different set of columns.
I looked in the screen designer in the customization editor, and I don't see a different view or anything, hopefully I'm just missing something simple.
Thanks
Scott
This is how I solved your mystery. First create a user field for SOShipment.
#region UsrReceiptBranchID
[PXInt]
[PXUIField(DisplayName="Receipt Branch ID")]
[GL.Branch()]
public virtual int? UsrReceiptBranchID { get; set; }
public abstract class usrReceiptBranchID : PX.Data.BQL.BqlInt.Field<usrReceiptBranchID> { }
#endregion
Next is the key part. I extended the data view delegate, and added an extra query to pull the POReceipt branch, when the Filter is Drop-Ship.
public virtual IEnumerable orders()
{
List<SOShipment> records = Base.orders().RowCast<SOShipment>().ToList();
if (Base.Filter.Current.Action.Contains("Drop"))
{
foreach (SOShipment sOShipment in records)
{
POReceipt receipt = PXSelect<POReceipt,
Where<POReceipt.receiptNbr,
Equal<Required<POReceipt.receiptNbr>>>>.Select(Base, sOShipment.ShipmentNbr);
if (receipt != null)
{
SOShipmentExt shipExt = PXCache<SOShipment>.GetExtension<SOShipmentExt>(sOShipment);
shipExt.UsrReceiptBranchID = receipt.BranchID;
}
}
return records;
}
else
{
return records;
}
}

Global Generic Field Update Event

I have 50+ custom paired fields "Inches" and "Centimeters", each enabled and editable. I need to update "Inches" if the user changed the value of "Centimeters" and visa verse. I was able to do this using SetValuePending on one of the paired fields and SetValueExt on the other during the Field Updated Event. My question, is there a way to do this on a higher level without having to do a Field_Updated event for all the 100+ fields. I know that Formulas would create a circular reference so cannot be used. Thanks
Well, you can use one method to handle FieldUpdated events for all fields you need using graph FieldUpdated.AddHandler method in constructor. To get a field name just extend a standard Acumatica FieldUpdated delegate with one additional parameter (name for example) and put it during the FieldUpdated.AddHandler call.
Here is an example with "Invoices and Memos" screen and ARInvoiceEntry graph.
public ARInvoiceEntry()
{
FieldUpdated.AddHandler(typeof(ARTran), typeof(ARTran.inches).Name, (sender, e) => CommonFieldUpdated(sender, e, typeof(ARTran.inches).Name));
FieldUpdated.AddHandler(typeof(ARTran), typeof(ARTran.centimeters).Name, (sender, e) => CommonFieldUpdated(sender, e, typeof(ARTran.centimeters).Name));
...
}
protected virtual void CommonFieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e, string name)
{
// do something
}
Moreover, you can add handlers dynamically using fields collection for example
foreach(var field in Caches[typeof(ARTran)].Fields)
{
// add handler depends on field name
}
You can do it by PXFormula + ExternalValue BQL expression (the same as PXRowUpdatedEventArgs.ExternalCall for example), which will prevent circular reference between pair fields. The idea is to calculate field only when a related field has been changed by the user from UI (ExternalCall = true) and skip calculation when related field updated by the formula (ExternalCall = false).
public class centimetersInInches : PX.Data.BQL.BqlDecimal.Constant<centimetersInInches>
{
public centimetersInInches() : base(2.54m) { }
}
[PXDecimal]
[PXUIField(DisplayName = "Inches")]
[PXUnboundDefault(TypeCode.Decimal, "0.0")]
[PXFormula(typeof(ExternalValue<Div<centimeters, centimetersInInches>>))]
public virtual decimal? Inches { get; set; }
public abstract class inches : PX.Data.BQL.BqlDecimal.Field<inches> { }
[PXDecimal]
[PXUIField(DisplayName = "Centimeters")]
[PXUnboundDefault(TypeCode.Decimal, "0.0")]
[PXFormula(typeof(ExternalValue<Mult<inches, centimetersInInches>>))]
public virtual decimal? Centimeters { get; set; }
public abstract class centimeters : PX.Data.BQL.BqlDecimal.Field<centimeters> { }
And aspx
<px:PXGridColumn DataField="Inches" CommitChanges="True" />
<px:PXGridColumn DataField="Centimeters" CommitChanges="True" />
You can use the RowUpdated event and compare the old row with the new row to detect which field changed. I agree that keeping all logic in a single method is preferable.
public virtual void DAC_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
DAC row = e.Row as DAC;
DAC oldRow = e.OldRow as DAC;
if (row == null || oldRow == null) return;
// Compare old row with new row to determine which field changed
if (row.Inches != oldRow.Inches)
{
// Inches field changed, update CM value
row.CM = row.Inches * INCHES_TO_CM_CONSTANT;
}
// Add more conditions for the other fields
[..]
}
I know that Formulas would create a circular reference so cannot be
used.
Yes I wouldn't recommend it either, you could use the DAC property Setter though.
public string _Inches
public virtual string Inches
{
get
{
return this._Inches;
}
set
{
this._Inches = value;
this.CM = value * INCHES_TO_CM_CONSTANT;
}
}
For all solution (except Formula/DAC attributes) I think a condition to stop recursion should be possible if it's absolutely necessary:
if (this.CM != value * INCHES_TO_CM_CONSTANT)
this.CM = value * INCHES_TO_CM_CONSTANT;
Ideally proper use/avoidance of SetValueExt to control when events are raised (Ext method raises events) would be enough to stop infinite loops.

How to Count records in a related table and allow user to override

I have a custom field on the CRActivity table in which I need to store the number of records in a related table. I am trying to set the field to the value when screen CR306030 opens. The user needs to be able to override the calculated number so, I'm thinking that I need logic on the calculation to check if the custom field is > 0, in which case, don't populate the custom field and assume it's already been set.
Previously, I've tried to do this in the Field_Selecting events but, this is not working. I'm thinking I might be able to use a PXFormula attribute. Any suggestions?
I tried making a custom attribute which is close but, it won't save the values to the db. The save button enables, I can click it and it looks like it saves but, no dice. Some mundane detail, I'm sure.....
Here's my custom attribute:
public class CFCountIfZeroAttribute : PXIntAttribute
{
public override void FieldSelecting(PXCache cache, PXFieldSelectingEventArgs e)
{
if (e.Row == null)
return;
CRActivity activity = (CRActivity)e.Row;
CRActivityExt activityExt = activity.GetExtension<CRActivityExt>();
if (activityExt.usrCustomField <= 0)
{
int aggregateValue = BQLToFind();
e.ReturnValue = aggregateValue;
cache.SetValue<CRActivityExt.usrCustomField>(e.Row, aggregateValue);
cache.IsDirty = true;
}
}
}
Thanks!
I don't think I've ever done a count within a PXFormula, but what if you created a custom attribute?
[DBUIInt()]
[EditableCount()]
public virtual int? CountField
public class EditableCountAttribute
{
public override void FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
if (e.Row != null)
{
//if CountField is 0, lookup the count from another table
}
}
}
This is just off the top of my head. You could pass the field you're counting into the attribute if you wanted to do this elsewhere.

Load value from popup to InventoryID field

am generating a pop on one new button click in stock Items screen, inside popup have two buttons, user select some data from fields in the popup and then click on ok, then inventoryId should be formed with some special characters and then it should display in InventoryID field. I can form the InventoryID but unable to display it in InventoryID field.
[PXButton]
[PXUIField(DisplayName = "Generate")]
public virtual void GenerateInv()
{
InventoryItemExt ext = Base.Item.Cache.GetExtension<InventoryItemExt>(Base.Item.Current);
Base.Item.Current.InventoryCD = ext.UsrInvId;
Base.Item.Cache.Insert(Base.Item.Current);
}
I had this issue before,
and the following code was provided by acumatica. you may try the same.
here in the below code, inventoryCD contains the value, i wanted to set.
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();
Also make sure your function have the correct input and the return type
IEnumerable GenerateInv(PXAdapter adapter)

Acumatica Scan barcode

In Acumatica project , on Receipt screen have a lookup button "Add Item". When Inventory lookup show dialog ( it's FromDetail template ), i will scan barcode from my bill. But, i must scan second times it to working.
How can i to filter grid details and set checked a row filtered according barcode ? And how can to know row count filtered? . Please help me.
The below figure illustrates.
snip code
Screen Receipt
You will be in a much better position with FieldVerifying handler implemented as follows for the INSiteStatusFilter.BarCode field to split scanned barcode and assign the new values both to BarCode field (though the PXFieldVerifyingEventArgs.New property) and custom unbound FilterQtySelected field. Then inside the FieldUpdated handler you will select all records from the detail grid, that satisfy filter condition and set Qty. Selected according to your unbound FilterQtySelected field:
public class INReceiptEntryExt : PXGraphExtension<INReceiptEntry>
{
public class INSiteStatusFilterExt : PXCacheExtension<INSiteStatusFilter>
{
#region QtySelected
public abstract class filterQtySelected : PX.Data.IBqlField
{
}
[PXQuantity]
public virtual decimal? FilterQtySelected { get; set; }
#endregion
}
public void INSiteStatusFilter_BarCode_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
{
var barCode = (string)e.NewValue;
string[] codes = barCode.Split(';');
decimal qtySelected;
if (codes.Length == 3 && decimal.TryParse(codes[2], out qtySelected))
{
e.NewValue = codes[1];
sender.GetExtension<INSiteStatusFilterExt>(e.Row).FilterQtySelected = qtySelected;
return;
}
sender.GetExtension<INSiteStatusFilterExt>(e.Row).FilterQtySelected = null;
}
public void INSiteStatusFilter_BarCode_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
INSiteStatusFilter filter = e.Row as INSiteStatusFilter;
var filterExt = filter.GetExtension<INSiteStatusFilterExt>();
if (string.IsNullOrEmpty(filter.BarCode) || !filterExt.FilterQtySelected.HasValue) return;
foreach(INSiteStatusSelected record in Base.sitestatus.Select())
{
record.Selected = true;
record.QtySelected = sender.GetExtension<INSiteStatusFilterExt>(e.Row).FilterQtySelected;
Base.sitestatus.Update(record);
}
}
}
You will need to add your custom 2D format support on the existing barcode infrastructure screens via a customization project.

Resources