How to work with Extension Table with projection INKitAssembly projection class? - acumatica

Below is extension DAC and Graph code, INRegisterKitAssemblyExt is a DAC, i have created a database table for that. i want to save usrSiteID value in INRegisterKitAssemblyExt(separate) database table. Please check how may i initialize extension DAC with INKitRegister DAC and save the value and how to use usrSiteId in UI?
[PXTable(typeof(INKitRegister.refNbr), typeof(INKitRegister.KitRevisionId))]
public class INRegisterKitAssemblyExt: PXCacheExtension<INKitRegister> {
#region RefNbr
public abstract class refNbr:PX.Data.BQL.BqlString.Field<refNbr> {
}
protected String _RefNbr;
[PXDBDefault(typeof(INKitRegister.refNbr))]
[PXDBString()]
[PXParent(typeof(Select<INKitRegister, Where<INKitRegister.refNbr, Equal<Current<refNbr>>,And<INKitRegister.kitRevisionID, Equal<Current<kitRevisionID>>>>>))]
public virtual String RefNbr {
get {
return this._RefNbr;
}
set {
this._RefNbr = value;
}
}
#endregion
#region KitRevisionID
public abstract class kitRevisionID:PX.Data.BQL.BqlString.Field<kitRevisionID> {
}
protected String _KitRevisionID;
[PXDBDefault(typeof(INKitRegister.kitRevisionID))]
[PXDBString()]
public virtual String KitRevisionID {
get {
return this._KitRevisionID;
}
set {
this._KitRevisionID = value;
}
}
#endregion
// My Fields as well as refNbr and KitRevison is also here
public virtual int? UsrQCSiteID {
get; set;
}
public abstract class usrQCSiteID:PX.Data.BQL.BqlInt.Field<usrQCSiteID> {
}
}
// Extension Graph
public class KitAssemblyEntryExt:PXGraphExtension<KitAssemblyEntry> {
}

INRegisterKitAssemblyExt in your code example is not a DAC.
DAC inherits from the IBqlTable base class.
INRegisterKitAssemblyExt in your code example is a DAC extension.
DAC extensions inherits from the PXCacheExtension base class.
You should never create database table for DAC extensions.
Custom fields in DAC extension will be persisted to the base DAC table automatically.
The main issue here is that INKitRegister is not DAC bound to a database table.
It's a Projection DAC and the INKitRegister database table does not exist.
The INKitRegister DAC projection points to the INRegister DAC:
[PXPrimaryGraph(typeof(KitAssemblyEntry))]
[PXCacheName(Messages.INKit)]
[PXProjection(typeof(Select2<INRegister, InnerJoin<INTran, On<INRegister.FK.KitTran>>>), Persistent=true)]
[Serializable]
public partial class INKitRegister : IBqlTable, ILSPrimary
You should create an extension on the INRegister DAC instead of INKitRegister because INRegister is bounded to an actual database table of the same name:
public class INRegisterKitAssemblyExt: PXCacheExtension<INRegister>

Related

add field on vendor screen

when I add a new field, in the payment configuration tab.
It adds the field in location to the database, but at the same time I create DAC addressExt, I don't understand why.
here is the DAC of each one that created me.
First.
the field is created in this table: Location
namespace PX.Objects.CR.Standalone
{
public class LocationExt : PXCacheExtension<PX.Objects.CR.Standalone.Location>
{
#region UsrTest
[PXDBBool]
[PXUIField(DisplayName="test")]
public virtual bool? UsrTest { get; set; }
public abstract class usrTest : PX.Data.BQL.BqlBool.Field<usrTest> { }
#endregion
}
}
second.
namespace PX.Objects.CR
{
public class AddressExt : PXCacheExtension<PX.Objects.CR.Address>
{
#region UsrTest
[PXDBBool]
[PXUIField(DisplayName = "test")]
public virtual bool? UsrTest { get; set; }
public abstract class usrTest : PX.Data.BQL.BqlBool.Field<usrTest> { }
#endregion
}
}
view image:
I hope you understand, I'm not good at English.
This is actually being done by design. The DAC you are editing is a Projection consisting of multiple DACs. Check this link out from Sergey Marenich
PXProjection uses 2 Data Access Classes for quotes:
One class represents the table – PX.Objects.CR.Standalone.CRQuote.
Another represents view as combination of DACs in select – PX.Objects.CR.CRQuote.
And to correctly work, custom field needs to be added in both of the places. And Projection field should be linked to table field using BqlField property of DBFieldAttributes.

Acumatica - Composite primary key

There is master-child table and master record has composite key on OrderNbr and RevisionNbr,
On UI we want to present the Selector for both the fields
OrderNbr with Max Revision number for Order number selector
Revision Number selector based on order Number selected ON UI.
also on UI we have function to create New revision, How we can create revision by Code, I am getting error of MUlti part query, when I defined IsKey= true for both the fields and tried to Save the data By
Graph.primaryView.Insert()
ForEach(UIRow){
Graph.ChildView.Insert
}
Graph.Persist();
Note the MAster table has Identity column in the SQL server has Key
Update-
Parent Table DAC -
#region TestSuiteID
public abstract class testSuiteID:PX.Data.IBqlField {
}
protected int? _TestSuiteID;
[PXDBIdentity()]
public virtual int? TestSuiteID {
get {
return this._TestSuiteID;
}
set {
this._TestSuiteID = value;
}
}
#endregion
#region TestSuiteCD
public abstract class testSuiteCD:PX.Data.IBqlField {
}
protected string _TestSuiteCD;
[PXDBString(50, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXDefault()]
[PXUIField(DisplayName = "Test Group ID")]
[PXSelector(typeof(EWQCTestSuite.testSuiteCD), typeof(EWQCTestSuite.testSuiteCD), typeof(EWQCTestSuite.revisionNo), typeof(EWQCTestSuite.name))]
public virtual string TestSuiteCD {
get {
return this._TestSuiteCD;
}
set {
this._TestSuiteCD = value;
}
}
#endregion
#region RevisionNo
public abstract class revisionNo:PX.Data.IBqlField {
}
protected int? _RevisionNo;
[PXDBInt(IsKey=true)]
[PXDefault(1)]
[PXUIField(DisplayName = "Revision No")]
public virtual int? RevisionNo {
get {
return this._RevisionNo;
}
set {
this._RevisionNo = value;
}
}
#endregion
Child Table Dac -
#region TestSuiteVariableID
public abstract class testSuiteVariableID:PX.Data.IBqlField {
}
protected int? _TestSuiteVariableID;
[PXDBIdentity(IsKey = true)]
public virtual int? TestSuiteVariableID {
get {
return this._TestSuiteVariableID;
}
set {
this._TestSuiteVariableID = value;
}
}
#endregion
#region TestSuiteID
public abstract class testSuiteID:PX.Data.IBqlField {
}
protected int? _TestSuiteID;
[PXDBInt()]
[PXDBDefault(typeof(EWQCTestSuite.testSuiteID))]
[PXParent(typeof(Select<EWQCTestSuite, Where<EWQCTestSuite.testSuiteID, Equal<Current<EWQCTestSuite.testSuiteID>>>>))]
public virtual int? TestSuiteID {
get {
return this._TestSuiteID;
}
set {
this._TestSuiteID = value;
}
}
#endregion
Note - Child table does not have MAster tab CD and revision number column as I added Identity column fr reference and have PXParent with Identity column.
Both Dac has other fields that I have not added here.
Other issue that I am facing is When I am Deleting the record I am getting some Primarykey reference error (Delete by default acumatica delete button on Primary DataView)
The multi-part query error is usually related to a master-detail (parent-child) query that resolves to more than one parent when executed. The child DAC should have a PXParent attribute that includes where clause on all the key fields.
[PXParent(typeof(Select<Master,
Where<Master.key1, Equal<Current<Child.key1>>,
And<Master.key2, Equal<Current<Child.key2>>>>>>))]
You should make sure all BQL queries in the DAC and the Graph that have such a relationship include a where filter or on join clause on all keys. Also make sure all key fields in DAC have IsKey=true and that the matching database fields where created as key fields in the database.
For composite key ..Instead of using PXGraph use PXRevisionableGraph.
This graph is part of manufactoring module and supports composite key..
All your key should be decorated with attribute inherited by AcctSubAttribute

how to add a field on the Project Quotes screen PQ000025

Good morning, I want to add a new field on this screen Project Quotes but in doing so I get this message, that the table does not exist.
How should or what is the way to achieve it.
Thanks in advance
Imagen 01
The added field in the database
enter image description here
He added the field in the database and then I generated my extension.
namespace PX.Objects.CR
{
public class PMQuoteExt : PXCacheExtension<PX.Objects.CR.CRQuote>
{
#region UsrNota
[PXDBString(-1, InputMask = "", BqlField = typeof(PMQuoteStandaloneExt.usrNotaText))]
[PXUIField(DisplayName = "Nota ")]
public virtual string UsrNotaText { get; set; }
public abstract class usrNotaText : IBqlField { }
#endregion
}
public class PMQuoteStandaloneExt : PXCacheExtension<PX.Objects.CR.Standalone.CRQuote>
{
#region UsrNota
[PXDBString(-1, InputMask = "")]
[PXUIField(DisplayName = "Nota ")]
public virtual string UsrNotaText { get; set; }
public abstract class usrNotaText : IBqlField { }
#endregion
}
}
public class PMQuoteMaint_Extension : PXGraphExtension<PMQuoteMaint>
{
public PXSelect<PX.Objects.CR.Standalone.CRQuote> Test;
}
However, when I record, it does not fill the field.
that I am making a mistake or doing wrong.
Can you tell me please.
Thank you
PMQuote is not an actual DB table, but a BQL projection between tables:
CR.Standalone.CRQuote
CROpportunityRevision
CR.Standalone.CROpportunity
The way that I would tackle this is:
Add the field in table CRQuote
Extend the graph and override the Projection with the inclusion of the new CRQuote field.
UPDATE:
Based on #HB_Acumatica suggestion, step 2 would get simplified to a DAC extension (no need for the Graph extension). Much simpler to maintain in subsequent Acumatica versions!
UPDATE 2:
The extended DACs do not look correct in your question. Keep in mind that you should extend the original table (CRQuote), and the projection in order to have the value persisted.
The following definition worked correctly on my end:
//Projection extension
public class PMQuoteExt : PXCacheExtension<PMQuote>
{
#region UsrCustomField
[PXDBString(100, BqlField = typeof(CRQuoteExt.usrCustomField))]
[PXUIField(DisplayName="Custom Field")]
public virtual string UsrCustomField { get; set; }
public abstract class usrCustomField : IBqlField { }
#endregion
}
//Actual Table extension
public class CRQuoteExt : PXCacheExtension<PX.Objects.CR.Standalone.CRQuote>
{
#region UsrCustomField
[PXDBString(100)]
[PXUIField(DisplayName="Custom Field")]
public virtual string UsrCustomField { get; set; }
public abstract class usrCustomField : IBqlField { }
#endregion
}

How to include field from a linked entity into Full-Text Entity Index?

I've added Customer Location to the Full-Text Entity Index, but cannot figure out how to get Address Line 1 from the Location to be part of the Full-Text Index and be displayed in the result.
To includes fields of linked entities (those which are in one-to-one relationship with the top-level entity on a data entry screen), it's required to specify what top-level entity field should be used along with the PXSelectorAttribute to retrieve the linked entity. Right after the top-level entity field acting as a bridge between the linked entities, you will specify fields of the secondary entity, which should be included into the Full-Text Index and/or be displayed in the result. Keep in mind, that only top-level entity fields decorated with PXSelectorAttribute or PXDimensionSelectorAttribute have the ability to act as a bridge between the linked entities.
For example, to include fields from the Address DAC into the Customer Location Full-Text Entity Index, you must add the DefAddressID field from the Location DAC before listing fields from the Address DAC:
public partial class Location : PX.Data.IBqlTable, IPaymentTypeDetailMaster, ILocation
{
...
public abstract class defAddressID : IBqlField { }
[PXDBInt()]
[PXDBChildIdentity(typeof(Address.addressID))]
[PXUIField(DisplayName = "Default Address", Visibility = PXUIVisibility.Invisible)]
[PXSelector(typeof(Search<Address.addressID>), DirtyRead = true)]
public virtual int? DefAddressID { get; set; }
...
}
The CustomerLocation DAC found in the following code snippet can serve as a perfect example of a custom DAC used to add Customer Location to the Full-Text Entity Index:
[Serializable]
[PXCacheName("Customer Location")]
[PXBreakInheritance]
public partial class CustomerLocation : SelectedCustomerLocation
{
public new abstract class bAccountID : IBqlField { }
[Customer(typeof(Search<Customer.bAccountID,
Where<Customer.type, Equal<BAccountType.customerType>,
Or<Customer.type, Equal<BAccountType.prospectType>,
Or<Customer.type, Equal<BAccountType.combinedType>>>>>),
IsKey = true)]
public override int? BAccountID { get; set; }
public new abstract class locationCD : IBqlField { }
public new abstract class descr : IBqlField { }
public new abstract class defAddressID : IBqlField { }
public new abstract class locType : IBqlField { }
public new abstract class noteID : IBqlField { }
[PXNote()]
[PXSearchable(SM.SearchCategory.CR, "{1} {2}: {3}",
new Type[] {
typeof(CustomerLocation.bAccountID),
typeof(Customer.acctCD),
typeof(CustomerLocation.locationCD),
typeof(CustomerLocation.descr) },
new Type[] {
typeof(CustomerLocation.bAccountID),
typeof(Customer.acctCD),
typeof(CustomerLocation.locationCD),
typeof(CustomerLocation.descr),
typeof(CustomerLocation.defAddressID),
typeof(Address.addressLine1),
typeof(Address.addressLine2),
typeof(Address.city),
typeof(Address.countryID) },
Line1Format = "{0} {2}",
Line1Fields = new Type[] {
typeof(CustomerLocation.descr),
typeof(CustomerLocation.defAddressID),
typeof(Address.addressLine1) },
Line2Format = "{1}",
Line2Fields = new Type[] {
typeof(CustomerLocation.defAddressID),
typeof(Address.addressLine2) },
WhereConstraint =
typeof(Where<CustomerLocation.locType, Equal<LocTypeList.customerLoc>,
Or<CustomerLocation.locType, Equal<LocTypeList.combinedLoc>>>),
MatchWithJoin = typeof(InnerJoin<Customer,
On<Customer.bAccountID, Equal<CustomerLocation.bAccountID>>>),
SelectForFastIndexing = typeof(Select2<CustomerLocation,
InnerJoin<Customer,
On<CustomerLocation.bAccountID, Equal<Customer.bAccountID>>>>)
)]
public override Guid? NoteID { get; set; }
}
Becides the DefAddressID field, which is used to include fields from the Address DAC to the Full-Text Entity Index, CustomerLocation also utilize CustomerAttribute attached to the BAccountID field to include Customer's natural application-wise AcctCD keys instead of the surrogate DB-level BAccountID keys. Last thing to mention is the PXBreakInheritanceAttribute required to prevent initialization of PXCache objects corresponding to base DACs when on Rebuild Full-Text Entity Index screen the system generates list of entities to be used by Full-Text Entity Index.

Add Attributes fields on Inventory Lookup

I want to add the attributes for my inventory lookup on Sales Order and Purchase Order, does anyone know how to? or any ideas?
Please refer below code example to include Attributes Columns in Selector and Grid Control utilizing out-of-box CRAttributesFieldAttribute.
Declare a class PXAddAtttributeColumns inherited from CRAttributesFieldAttribute.
public class PXAddAtttributeColumns : CRAttributesFieldAttribute
{
string[] _names;
bool _IsForSelector;
public PXAddAtttributeColumns(string[] names, Type entityType, Type entityIDField, Type classIDField, bool IsForSelector = true)
: base(entityType, entityIDField, classIDField)
{
_names = names;
_IsForSelector = IsForSelector;
}
public override void CacheAttached(PXCache sender)
{
this._IsActive = true;
base.CacheAttached(sender);
}
protected override void AttributeFieldSelecting(PXCache sender, PXFieldSelectingEventArgs e, PXFieldState state, string attributeName, int idx)
{
if (_names.Any(attributeName.Equals))
{
//Out-of-box DisplayName is prefixed with "$Attributes$-" - if you need to take that off.
state.DisplayName = (!String.IsNullOrEmpty(state.DisplayName)) ? (state.DisplayName.Replace("$Attributes$-", "")) : attributeName;
state.Visible = true;
//Requires AutoGenerateColumns="AppendDynamic" for PXGrid Control for dynamic Attribute columns creation
state.Visibility = (_IsForSelector) ? PXUIVisibility.SelectorVisible : PXUIVisibility.Dynamic;
}
base.AttributeFieldSelecting(sender, e, state, attributeName, idx);
}
public override void CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e)
{
base.CommandPreparing(sender, e);
if (e.BqlTable == null && aggregateAttributes && sender.GetItemType().IsDefined(typeof(PXProjectionAttribute), true))
{
e.BqlTable = _BqlTable;
}
}
}
To include attributes as Columns in Inventory Look up, declare DAC Extension as below:
public class InventoryItemPXExt : PXCacheExtension<PX.Objects.IN.InventoryItem>
{
#region Attributes
public abstract class attributes : IBqlField { }
[PXAddAtttributeColumns(new[] { "ASSETID", "HWMODEL" },
typeof(CSAnswerType.inventoryAnswerType),
typeof(InventoryItem.inventoryID),
typeof(InventoryItem.itemClassID))]
public virtual string[] Attributes { get; set; }
#endregion
}
Fields will show up as below:
Search can be Enabled on Attribute Columns by setting FilterByAllFields to True
To include attributes as Columns in Sales Order Details Grid, declare DAC Extension as below:
public class SOLineExtension : PXCacheExtension<SOLine>
{
public abstract class itemAttributes : IBqlField { }
[PXAddAtttributeColumns(new[] { "ASSETID", "HWMODEL" },
typeof(CSAnswerType.inventoryAnswerType),
typeof(SOLine.inventoryID),
typeof(InventoryItem.itemClassID), false)]
public virtual string[] ItemAttributes { get; set; }
}
Make sure to specify AutoGenerateColumns="AppendDynamic" for PXGrid control dynamic Attribute columns creation
Fields will show up as below:
To include attributes as Columns in grid of Add Stock Item Dialog, declare DAC Extension as below:
public class SOSiteStatusSelectedExtension : PXCacheExtension<SOSiteStatusSelected>
{
public abstract class itemAttributes : IBqlField { }
[PXAddAtttributeColumns(new[] { "ASSETID", "HWMODEL" },
typeof(CSAnswerType.inventoryAnswerType),
typeof(InventoryItem.inventoryID),
typeof(InventoryItem.itemClassID), false)]
public virtual string[] ItemAttributes { get; set; }
}
Make sure to specify AutoGenerateColumns="AppendDynamic" for PXGrid control dynamic Attribute columns creation
Fields will show up as below:
Note: This example is applicable to 5.3 series – Build 5.30.1367 onwards.
Updated solution for versions later than 20R1:
Below is the sample scenario to add custom attributes to both CustomerID and InventoryID lookups of Sales Orders (SO301000) screen.
Create the required attributes from Attributes (CS205000) screen.
Add the necessary attribute to the corresponding Customer Classes (AR201000) screen to be added to the CustomerID lookup and to the corresponding Item Classes (IN201000) screen to be added to the InventoryID lookup.
Create a new Attribute class CustomerAttributeSetFieldsAttribute extending CustomerActiveAttribute (since it is used in CustomerID) and override SetColumns by rewriting the same in order to change the FieldList and HeaderList.
public class CustomerAttributeSetFieldsAttribute : CustomerActiveAttribute
{
public static void SetColumns(PXCache cache, string field, string[] fieldList, string[] headerList)
{
PXSelectorAttribute.SetColumns(cache, field, fieldList, headerList);
foreach (CustomerAttributeSetFieldsAttribute attr in cache.GetAttributes(field).OfType<CustomerAttributeSetFieldsAttribute>())
{
attr._FieldList = fieldList;
attr._HeaderList = headerList;
}
}
}
Override Initialize method and call Activate for activating the attribute by passing proper cache - BAccountR - for CustomerID and InventoryItem - for InventoryID. Also, call SetColumns from the custom attribute for CustomerID CustomerAttributeSetFieldsAttribute and PXSelectorAttribute for InventoryID and pass the cache type (where the lookup is present), field (field name), fieldList (list of names of all the fields including the attributes) and headerList (list of names of all the headers including the attributes).
Override the attributes to merge the newly added attribute to CustomerID by adding CustomerAttributeSetFields to SOOrder_CustomerID_CacheAttached method.
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public override void Initialize()
{
base.Initialize();
//for InventoryID lookup
CR.CRAttributesFieldAttribute.Activate(Base.Caches[typeof(InventoryItem)]);
PXSelectorAttribute.SetColumns(Base.Caches[typeof(SOLine)],
"InventoryID", new string[] { "InventoryCD", "Descr", "itemClassID", "Color_ATTRIBUTES" },
new string[] { "InventoryCD", "Descr", "itemClassID", "$Attributes$-Color" });
//for CustomerID lookup
CR.CRAttributesFieldAttribute.Activate(Base.Caches[typeof(BAccountR)]);
CustomerAttributeSetFieldsAttribute.SetColumns(Base.Caches[typeof(SOOrder)],
"CustomerID", new string[] { "AcctCD", "acctName", "COMPREV_Attributes" },
new string[] { "AcctCD", "acctName", "$Attributes$-Company Revenue" });
}
[PXMergeAttributes(Method = MergeMethod.Merge)]
[CustomerAttributeSetFields]
protected virtual void SOOrder_CustomerID_CacheAttached(PXCache sender)
{
}
}
Note: Since Customer DAC is derived from BAccount and CustomerActive attribute is derived from Customer, it has the cache type BAccountR and only the attributes which are of the same cache type are available to add to the CustomerID popup. If the user needs to add other attributes of different cache type, it will be better to create a new Attribute and use that instead of CustomerActive.

Resources