Add Attribute in “Add Item” dialog box in Purchase Order screen of Acumatica - acumatica

How can I add an Attribute column from "Stock Items" screen to "Add Item" dialog box of Purchase Order screen. I want to add the following attribute from Stock Items screen to the "Add Item" Dialog box of Purchase Order Screen.
Please review the images below for Stock Item and Purchase Order Screens.
I am able to get the field in the inventory lookup of PO, the values did not populated.
here goes my code....
namespace PX.Objects.PO
{
[PXProjection(typeof(Select<CSAnswers, Where<CSAnswers.refNoteID, Equal<POSiteStatusSelected.noteID>,
And<CSAnswers.attributeID, Equal<AttribMyAttribute>>>>), Persistent = false)]
public class POSiteStatusSelectedExt : PXCacheExtension<PX.Objects.PO.POSiteStatusSelected>
{
#region UsrItemType
[PXDBString(10, IsFixed = true, BqlField = typeof(CSAnswers.value))]
[PXUIField(DisplayName = "Item Type")]
//[PXDBScalar(typeof(Search<CSAnswers.value, Where<CSAnswers.refNoteID, Equal<POSiteStatusSelected.noteID>,
// And<CSAnswers.attributeID, Equal<AttribMyAttribute>>>>))]
public virtual string UsrItemType { get; set; }
public abstract class usrItemType : IBqlField { }
#endregion
}
public class AttribMyAttribute : Constant<string>
{
public AttribMyAttribute() : base("ITEMTYPE") { }
}
}
I have created a DAC extension of POSiteStatusSeleted view and added my custom field which is a non-persisted field. There is noteId field in the POSiteStatusSeleted which is of type InventoryItem.noteID, i tried to use the same in the PXDBScalar attribute(the code line is commented), this also didn't work out, it was showing an error for "Unable to convert System.Int32 to System.String".

Updated Answer: Because of the projection, we have to create a new class that inherits the DAC and uses the [PXSubstitute] attribute. The nature of PXSubstitute means that this will not be a DAC extension or even part of a Graph Extension. In my testing, I tried encapsulating this in a graph extension on POOrderEntry, and it did not work. By following the instructions of the stack overflow post below, I was able to create an Attribute called ITEMTYPE, assign it to one of my Item Classes, replace the PXProjection with an enhanced version that includes a left join back to the attribute table (CSAnswers) and then add it to the screen's smart panel grid.
Extend Acumatica Projection Based DAC Query
In the code sample below, the magic is in PXSubstitute, which will take the new class that you create and inherit from the base DAC and replace that base DAC with your new one. If you specify a graph, it will perform the substitution in only that graph (or each graph you specify - 1 per PXSubstitute attribute used). If you do not specify a graph, it will override the base DAC in every case it is used within the xRP Framework.
Code to perform the stated modification:
using PX.Data;
using PX.Objects.AP;
using PX.Objects.Common.Bql;
using PX.Objects.CS;
using PX.Objects.IN;
using System;
namespace PX.Objects.PO
{
[System.SerializableAttribute()]
[PXProjection(typeof(Select2<InventoryItem,
LeftJoin<CSAnswers,
On<CSAnswers.refNoteID, Equal<InventoryItem.noteID>,
And<CSAnswers.attributeID, Equal<AttribItemType>>>,
LeftJoin<INSiteStatus,
On<INSiteStatus.inventoryID, Equal<InventoryItem.inventoryID>, And<INSiteStatus.siteID, NotEqual<SiteAttribute.transitSiteID>>>,
LeftJoin<INSubItem,
On<INSiteStatus.FK.SubItem>,
LeftJoin<INSite,
On<INSiteStatus.FK.Site>,
LeftJoin<INItemXRef,
On<INItemXRef.inventoryID, Equal<InventoryItem.inventoryID>,
And2<Where<INItemXRef.subItemID, Equal<INSiteStatus.subItemID>,
Or<INSiteStatus.subItemID, IsNull>>,
And<Where<CurrentValue<POSiteStatusFilter.barCode>, IsNotNull,
And<INItemXRef.alternateType, Equal<INAlternateType.barcode>>>>>>,
LeftJoin<INItemPartNumber,
On<INItemPartNumber.inventoryID, Equal<InventoryItem.inventoryID>,
And<INItemPartNumber.alternateID, Like<CurrentValue<POSiteStatusFilter.inventory_Wildcard>>,
And2<Where<INItemPartNumber.bAccountID, Equal<Zero>,
Or<INItemPartNumber.bAccountID, Equal<CurrentValue<POOrder.vendorID>>,
Or<INItemPartNumber.alternateType, Equal<INAlternateType.cPN>>>>,
And<Where<INItemPartNumber.subItemID, Equal<INSiteStatus.subItemID>,
Or<INSiteStatus.subItemID, IsNull>>>>>>,
LeftJoin<INItemClass,
On<InventoryItem.FK.ItemClass>,
LeftJoin<INPriceClass,
On<INPriceClass.priceClassID, Equal<InventoryItem.priceClassID>>,
LeftJoin<Vendor,
On<Vendor.bAccountID, Equal<InventoryItem.preferredVendorID>>,
LeftJoin<INUnit,
On<INUnit.inventoryID, Equal<InventoryItem.inventoryID>,
And<INUnit.unitType, Equal<INUnitType.inventoryItem>,
And<INUnit.fromUnit, Equal<InventoryItem.purchaseUnit>,
And<INUnit.toUnit, Equal<InventoryItem.baseUnit>>>>>>>>>>>>>>>,
Where2<CurrentMatch<InventoryItem, AccessInfo.userName>,
And2<Where<INSiteStatus.siteID, IsNull, Or<INSite.branchID, IsNotNull, And2<CurrentMatch<INSite, AccessInfo.userName>,
And<Where2<FeatureInstalled<FeaturesSet.interBranch>,
Or2<SameOrganizationBranch<INSite.branchID, Current<POOrder.branchID>>,
Or<CurrentValue<POOrder.orderType>, Equal<POOrderType.standardBlanket>>>>>>>>,
And2<Where<INSiteStatus.subItemID, IsNull,
Or<CurrentMatch<INSubItem, AccessInfo.userName>>>,
And<InventoryItem.stkItem, Equal<boolTrue>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.inactive>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.unknown>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.markedForDeletion>,
And<InventoryItem.itemStatus, NotEqual<InventoryItemStatus.noPurchases>>>>>>>>>>), Persistent = false)]
//[PXSubstitute(GraphType = typeof(POOrderEntry))]
[PXSubstitute]
public partial class POSiteStatusSelectedCst : POSiteStatusSelected
{
#region UsrItemType
[PXDBString(10, BqlField = typeof(CSAnswers.value))]
[PXUIField(DisplayName = "Item Type")]
public string UsrItemType { get; set; }
public abstract class usrItemType : PX.Data.BQL.BqlString.Field<usrItemType> { }
#endregion
}
public class AttribItemType : PX.Data.BQL.BqlString.Constant<AttribItemType>
{
public AttribItemType() : base("ITEMTYPE") { }
}
}

Related

How can I set an Attribute as a Parameter in Acumatica Report Designer?

I have created an attribute for Stock Item screen, I want that attribute as a parameter in my report .rpx file. My attribute is of combo type attribute.
I wrote a small customization which shows how to add a specific attribute to the report parameter.
First create a custom DAC. In my case, I chose to expose the INDUSTRY attribute.
public class IndustryAttr : IBqlTable
{
#region UsrIndustry
[PXDBString]
[PXUIField(DisplayName = "Industry")]
[PXSelector(typeof(Search<CSAttributeDetail.valueID,
Where<CSAttributeDetail.attributeID,Equal<ind>>>),
typeof(CSAttributeDetail.valueID),
typeof(CSAttributeDetail.description))]
public virtual string UsrIndustry { get; set; }
public abstract class usrIndustry : PX.Data.BQL.BqlString.Field<usrIndustry> {}
#endregion
}
public class ind : PX.Data.BQL.BqlString.Constant<ind>
{
public ind()
: base("INDUSTRY")
{
}
}
Next I added the parameter in the report. Pay attention to the attribute declaration.
Now the Industry attribute appears as the selector

Show unbound field with PXFormula

I'm trying to show a value calculated with PXFormula but the field doesn't show the value.
I have my CustomDAC named EDITran
public class EDITran : IBqlTable
{
#region Doctype
[PXDBString(50, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Doctype")]
[PXStringList
(new string[]
{"SO", "SHI", "INV" },
new string[]
{"Sales Order", "Shipment", "Invoice"}
)]
public virtual string Doctype { get; set; }
public abstract class doctype : PX.Data.BQL.BqlString.Field<doctype> { }
#endregion
#region Erprefnbr
[PXDBString(30, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "ERP RefNbr")]
public virtual string Erprefnbr { get; set; }
public abstract class erprefnbr : PX.Data.BQL.BqlString.Field<erprefnbr> { }
#endregion
#region Sync
[PXDBBool()]
[PXUIField(DisplayName = "Sync")]
public virtual bool? Sync { get; set; }
public abstract class sync : PX.Data.BQL.BqlBool.Field<sync> { }
#endregion
}
}
so I what to show the value of sync field on the Sales Order screen. The key is the ERP RefNbr (which would be SOOrder.OrderNbr)
I have added the custom non persisted field on the SOOrderExt DAC with this attributes
using PX.Objects.SO;
[PXBool]
[PXUIField(DisplayName="EDI Sync" , Enabled = false)]
[PXFormula(typeof(Selector<SOOrder.orderNbr,
Selector<EDITran.erprefnbr,
EDITran.sync>>))]
But when I added a record in EDITran and try to visualize it in SOOrder Form and I checked that EDITran.Sync = 1, it doesn't show the saved value.
Sales Order Screen
What I'm I doing wrong? Is the PXFormula correctly used?
PXFormula used incorrectly. PXFormula attribute works only with current DAC (which is SOOrder) or foreign DAC, existing in PXSelector join condition (you can use Selector keyword to get it).
For example, here is the SOOrder.OrderNbr selector declaration
[SO.RefNbr(typeof(Search2<SOOrder.orderNbr,
LeftJoinSingleTable<Customer, On<SOOrder.customerID, Equal<Customer.bAccountID>,
And<Where<Match<Customer, Current<AccessInfo.userName>>>>>>,
Where<SOOrder.orderType, Equal<Optional<SOOrder.orderType>>,
And<Where<Customer.bAccountID, IsNotNull,
Or<Exists<Select<SOOrderType,
Where<SOOrderType.orderType, Equal<SOOrder.orderType>,
And<SOOrderType.aRDocType, Equal<ARDocType.noUpdate>,
And<SOOrderType.behavior, Equal<SOBehavior.sO>>>>>>>>>>,
OrderBy<Desc<SOOrder.orderNbr>>>), Filterable = true)]
public virtual String OrderNbr
you can get some fields from the related Customer record, using Selector keyword
[PXFormula(typeof(Selector<
SOOrder.orderNbr,
Customer.consolidateStatements>))]
As a result, there are two possible solutions:
1) Rewrite SOOrder.OrderNbr selector declaration with your EDITran DAC
...
[SO.RefNbr(typeof(Search2<SOOrder.orderNbr,
LeftJoinSingleTable<Customer, On<SOOrder.customerID, Equal<Customer.bAccountID>,
And<Where<Match<Customer, Current<AccessInfo.userName>>>>>,
LeftJoin<EDITran, On<EDITran.doctype, Equal<SOOrder.orderType>,
And<EDITran.erprefnbr, Equal<SOOrder.orderNbr>>>>>,
Where<SOOrder.orderType, Equal<Optional<SOOrder.orderType>>,
And<Where<Customer.bAccountID, IsNotNull,
Or<Exists<Select<SOOrderType,
Where<SOOrderType.orderType, Equal<SOOrder.orderType>,
And<SOOrderType.aRDocType, Equal<ARDocType.noUpdate>,
And<SOOrderType.behavior, Equal<SOBehavior.sO>>>>>>>>>>,
OrderBy<Desc<SOOrder.orderNbr>>>), Filterable = true)]
public virtual String OrderNbr
Then it will be possible to get you field from there
[PXFormula(typeof(Selector<
SOOrder.orderNbr,
EDITran.sync>))]
2) Use PXDBScalar attribute to just get what you need. Note this will be a separate request to the database!!
...
[PXBool]
[PXDBScalar(typeof(Search<EDITran.sync,
Where<EDITran.doctype, Equal<SOOrder.orderType>,
And<EDITran.erprefnbr, Equal<SOOrder.orderNbr>>>>))]
public virtual bool? Sync
I'm not sure that's the right use of PXFormula. Here's the reference I normally use when I need to use PXFormula. See if it helps you simplify your PXFormula. You may need to simplify to a single Selector and define a foreign key to be able to complete your lookup.
Also, are you sure that the database contains the values that you expect? I often find that my problem is not where I think, and your issue may lie in setting the values or writing them to the database in your business logic.
It appears that you need the PXFormula to look to your EDITran table to find the record identified by the key (1st field specified in Selector) to then return back the value of the second field specified, which would reside in EDITran.
From Acumatica Developers Blog (AsiaBlog):
Selector
Selector does following:
Fetches a PXSelectorAttribute defined on the foreign key field (KeyField) of the current DAC.
Fetches the foreign data record currently referenced by the selector.
Using calculates and returns an expression on that data record as defined by ForeignOperand.
public class APVendorPrice : IBqlTable
{
// Inventory attribute is an aggregate containing a PXSelectorAttribute
// inside, which is also valid for Selector<>.
[Inventory(DisplayName = "Inventory ID")]
public virtual int? InventoryID
[PXFormula(typeof(Selector<
APVendorPrice.inventoryID,
InventoryItem.purchaseUnit>))]
public virtual string UOM { get; set; }
}
From that, I'd expect your PXFormula to look more like:
[PXFormula(typeof(Selector<
SOOrder.orderNbr,
EDITran.sync>))]
... assuming you have enough defined to tell Acumatica how to relate SOOrder.orderNbr to EDITran.erprefnbr.

How to change the Display Name for one of the PXSelector fields

I need to change the Display Name to "Primary Vendor" for a BAccount.acctName field, which is the last field to display in the PXSelector that I have created.
I have tried creating an field Extension which does the trick, but this option also renames the field for another inquiry page, therefore I cannot use it.
The following is my code:
Selector
[PXNonInstantiatedExtension]
public class SO_SOLine_ExistingColumn :
PXCacheExtension<PX.Objects.SO.SOLine>
{
#region InventoryID
[PXMergeAttributes(Method =
MergeMethod.Append)]
[PXSelector(typeof(Search2<InventoryItem.inventoryCD,
LeftJoin<BAccount, On<BAccount.bAccountID,
Equal<InventoryItem.preferredVendorID>>>,
Where<InventoryItem.descr, IsNotNull>>),
typeof(InventoryItem.inventoryID),
typeof(InventoryItem.inventoryCD),
typeof(InventoryItem.descr),
typeof(InventoryItem.postClassID),
typeof(InventoryItem.itemStatus),
typeof(InventoryItem.itemType),
typeof(InventoryItem.baseUnit),
typeof(InventoryItem.salesUnit),
typeof(InventoryItem.purchaseUnit),
typeof(InventoryItem.basePrice),
typeof(BAccount.acctName), ValidateValue = false) ]
public int? InventoryID { get; set; }
#endregion
}
Field Extension
public class BAccountExt : PXCacheExtension<PX.Objects.CR.BAccount>
{
#region UsrCustomField
[PXDBString(250, IsUnicode = true, BqlField =
typeof(BAccountR.acctName))]
[PXUIField(DisplayName = "Primary Vendor")]
public virtual string AcctName { get; set; }
public abstract class acctName : IBqlField
{
}
#endregion
}
As you found out the cache extension modifications applies to all screens who use that DAC. There is another extension mechanism applied on a per graph basis called CacheAttached that is applied after the cache extension.
To use it first you need to identify the graph of the screen you want to customize and the DAC field you want to modify. You can use the inspect element feature for this. In this example the graph for Customers screen is 'CustomerMaint' and the DAC field is 'Customer.acctName':
Once you have that information you can create an extension for that graph and extend the DAC field inside it. DAC field extensions defined in the graph using the CacheAttached method will only apply to screens who uses that graph:
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXUIField(DisplayName = "Display Name For Customers Graph")]
public virtual void Customer_AcctName_CacheAttached(PXCache sender)
{
}
}
The prototype convention for CacheAttached extensions is:
void DAC_DACField_CacheAttached(PXCache sender) { }
You change DAC and DACField to the field you are targeting. Method definition (body) should remain empty. The attributes decorating the CacheAttached method will apply to the field you're customizing. With attribute PXMerge you can tweak how the CacheAttached extension is applied, it allows to merge the field new attributes of the extension with the base one or completely replace the base attributes.
For more details look at this blog post:
http://asiablog.acumatica.com/2017/01/append-and-replace-of-dacs-attributes.html
you can also try like below but this is limited to the specific graph.
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
public override void Initialize()
{
PXUIFieldAttribute.SetDisplayName<Customer.acctName>(Base.BAccount.Cache, "Primary Vendor");
}
}

Adding Owner Name in the Purchase Order Lookup screen

I would like to add the Owner Name (on the PO Screen) in the Purchase Order>Order Nbr. field lookup screen. I tried to manually add the following in the Data Class for OrdNbr but it didn't bring the Employee name in the lookup screen. Can you please help or let me know if i am missing something.
Here is the full code i am trying(screenshot attached)
[PXCustomizeSelectorColumns(
typeof(PX.Objects.PO.POOrder.orderType),
typeof(PX.Objects.PO.POOrder.orderNbr),
typeof(PX.Objects.PO.POOrder.vendorRefNbr),
typeof(PX.Objects.PO.POOrder.orderDate),
typeof(PX.Objects.PO.POOrder.status),
typeof(PX.Objects.PO.POOrder.vendorID),
typeof(PX.Objects.PO.POOrder.vendorID_Vendor_acctName),
typeof(PX.Objects.PO.POOrder.vendorLocationID),
typeof(PX.Objects.PO.POOrder.curyID),
typeof(PX.Objects.PO.POOrder.curyOrderTotal),
typeof(PX.Objects.PO.POOrder.sOOrderType),
typeof(PX.Objects.PO.POOrder.sOOrderNbr),
typeof(PX.Objects.PO.POOrder.orderDesc),
typeof(PX.Objects.CR.CREmployee.acctCD),
typeof(PX.Objects.CR.CREmployee.bAccountID),
typeof(PX.Objects.CR.CREmployee.acctName))]
Many Thanksenter image description here
Since POOrder.employeeID has a PXSelector attribute on its definition:
And this Selector has a DescriptionField assigned:
On this case you can add Owner name by adding this line of code to your CacheExtension file(This will obtain that DescriptionField for the EmployeeID field):
public abstract class employeeID_CREmployee_acctName : PX.Data.IBqlField { }
See Snippet below:
namespace PX.Objects.PO
{
[PXNonInstantiatedExtension]
public class PO_POOrder_ExistingColumn : PXCacheExtension<PX.Objects.PO.POOrder>
{
#region OwnerName
public abstract class employeeID_CREmployee_acctName : PX.Data.IBqlField
{ }
#endregion
#region OrderNbr
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXCustomizeSelectorColumns(
typeof(PX.Objects.PO.POOrder.orderType),
typeof(PX.Objects.PO.POOrder.orderNbr),
typeof(PX.Objects.PO.POOrder.vendorRefNbr),
typeof(PX.Objects.PO.POOrder.orderDate),
typeof(PX.Objects.PO.POOrder.status),
typeof(PX.Objects.PO.POOrder.employeeID),
typeof(PX.Objects.PO.PO_POOrder_ExistingColumn.employeeID_CREmployee_acctName),
typeof(PX.Objects.PO.POOrder.vendorID),
typeof(PX.Objects.PO.POOrder.vendorID_Vendor_acctName),
typeof(PX.Objects.PO.POOrder.vendorLocationID),
typeof(PX.Objects.PO.POOrder.curyID),
typeof(PX.Objects.PO.POOrder.curyOrderTotal),
typeof(PX.Objects.PO.POOrder.sOOrderType),
typeof(PX.Objects.PO.POOrder.sOOrderNbr))]
public string OrderNbr { get; set; }
#endregion
}
}
Please notice that in case the POOrder.EmployeeID field would not have the "DescriptionField" set on the PXSelector Definition, you would have to modify the PXSelector of the OrderNbr to add a LeftJoin on the Desired Table(CREmployee on this case) so you could use the desired fields and add them to the PXCustomizeSelectorColumns attribute.

Accessing user-defined fields added via an extension in Acumatica

I have a custom field called 'UsrIsTeacherBook` which was added to the InventoryItem with the following extension:
namespace Lasalle.TeacherBooks
{
public class InventoryItem_TeacherBooks_Extension : PXCacheExtension<InventoryItem>
{
[PXDBBool]
[PXUIField(DisplayName = "Is Teacher Book")]
public virtual bool? UsrIsTeacherBook { get; set; }
public abstract class usrIsTeacherBook : IBqlField { }
}
}
I need to be able to access the value of this IsTeacherBook field from the SOLine grid on the SalesOrder screen. I added a custom field UsrTeacherBook to the SOLine grid on the sales order screen, but I cannot figure out how to populate this field with the value of InventoryItem UsrIsTeacherBook.
I tried customizing the attributes on the SOLine field in the following way:
[PXDBBool]
[PXUIField(DisplayName="Teacher Manual", Visible = true, Enabled = false)]
[PXFormula(typeof(Selector<SOLine.inventoryID, InventoryItemExt.usrIsTeacherBook>))]
But this produced a validation error, "The type name 'usrIsTeacherBook' does not exist in the type 'PX.Objects.IN.InventoryItemExt'."
What is the correct way to access the InventoryItem IsTeacherBook field to populate my field on the SOLine grid?
Your extension class name is InventoryItem_TeacherBooks_Extension, not InventoryItemExt used in PXFormulaAttribute. You should either change your extension name to InventoryItemExt or modify PXFormula declaration with InventoryItem_TeacherBooks_Extension.usrIsTeacherBook

Resources