Search4 Selector with not Resolving Correctly in MySQL - acumatica

I have added a new field called UsrStockLocation to the SOLine DAC, this field has a selector that searches all past entries and shows them without duplicates. This worked in 2017R2 and works in 2018R2 if the Acumatica site is using MSSQL, however, if the 2018R2 site is using MySQL I receive this error when I click the magnifying glass on the field:
Unknown column 'SOLineExtension.UsrStockLocation' in 'field list'
It looks like Acumatica is passing the class name from the DAC extension on to the DB instead of SOLine. The column UsrStockLocation is created properly in the SOLine table in the DB.
Here is the code for the DAC extension:
using PX.Data;
namespace PX.Objects.SO
{
public class SOLineExtension : PXCacheExtension<PX.Objects.SO.SOLine>
{
#region Stock Location
[PXDBString()]
[PXUIField(DisplayName="Stock Location")]
[PXSelector(typeof(Search4<SOLineExtension.usrStockLocation, Where<SOLineExtension.usrStockLocation, IsNotNull>, Aggregate<GroupBy<SOLineExtension.usrStockLocation>>>), ValidateValue = false)]
[PXCustomizeSelectorColumns(typeof(SOLineExtension.usrStockLocation))]
public virtual string UsrStockLocation { get; set; }
public abstract class usrStockLocation : IBqlField { }
#endregion
}
}
Am I missing something here? Is there a different way that I am supposed to do this for MySQL vs MSSQL?

Related

Customization Default library

Could anybody help me with acumatica? I have an application, witch connect to acumatica with acumatica libraries: Auth, Default_18.200.001, RESTClient from here: https://github.com/Acumatica/AcumaticaRESTAPIClientForCSharp I am using it like submodules - if somesings will change on git - I always can update it
I needed to add custom fields to the Project form. I did it - added fields, posted changes. After that, I created a new endpoint inheriting it from default endpoint - and the new fields became available to me when working with the Project entity. I achieved this by creating classes that inherit from api and the base model with overriding the GetEntityName() method.
If I need to change the fields, I will have to create new inheritance classes.
Perhaps there is some standard way to support customization fields? And I just didn't find it.
My Api extension:
public class ProjectExtApi : EntityAPI<ProjectExt>
{
public ProjectExtApi(Configuration configuration) : base(configuration)
{ }
protected override string GetEntityName()
{
return "Project"; //base code: return typeof(EntityType).Name;
}
}
and model:
[DataContract]
public class ProjectExt : Project
{
[DataMember(Name = "TestDate", EmitDefaultValue = false)]
public DateTimeValue TestDate { get; set; }
}
My answer is related to custom fields inside Acumatica product. Custom fields should be added with DAC extensions (PXCacheExtension class), example:
public class MyContractExt : PXCacheExtension<Contract>
{
#region UsrDateTime
[PXDBDateAndTime]
public virtual DateTime? UsrDateTime { get; set; }
public abstract class usrDateTime : BqlDateTime.Field<usrDateTime> { }
#endregion
}
Note that PMProject DAC in Acumatica is inheriting from Contract DAC and the field will be persisted in the Contract table.
If the field requires to be persisted in database (with PXDBxyz.. attribute instead of PXxyz..) it requires a database script.
It is recommended to add custom field with a customization. When creating a custom field in the Data Access section of a customization the wizard will automatically create the database script to add the column to the table.
External link, tutorial:
https://www.acu-connect.com/2019/02/27/customizing-acumatica-erp-adding-a-new-field-to-an-existing-screen/

PXSelector attribute suppress Error on form

Good day
I have created a custom Location field for warehouse locations:
#region UsrTOLocation
[PXString]
[PXUIField(DisplayName = "To Location")]
[PXSelector(typeof(Search<
INLocation.locationCD,
Where<INLocation.siteID, Equal<Current<INRegister.toSiteID>>>>))]
public virtual string UsrTOLocation { get; set; }
public abstract class usrTOLocation : PX.Data.BQL.BqlString.Field<usrTOLocation> { }
#endregion
When the location does not exist I create it using code in a button.
Since I have added the PXSelector to the above field I keep getting an error when it doesn't find the locations. This is correct because I still need to create it
Is there a way to suppress the error that it is not finding the location?
You can use ValidateValue property of the PXSelector attribute.
For instance:
[PXSelector(..., ValidateValue = false)]
It disables validation and therefore error appearing in PXSelector attribute

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");
}
}

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

Get combination of CD and description for PXSelector

I'm trying to use a Selector to lookup up customers, and I want it to show the CD along with the description in the field. I've seen this many times in Acumatica - and I thought I knew how to do it, but it's not working. Here is my code:
#region CustomerLookup
public abstract class customerLookup : PX.Data.IBqlField
{
}
protected string _CustomerLookup;
[PXDBString(100, IsUnicode = true)]
[PXUIField(DisplayName = "Customer Lookup")]
[PXSelector(typeof(Customer.acctCD)
,typeof(Customer.acctCD)
,typeof(Customer.acctName)
,DescriptionField=typeof(Customer.acctName))]
public virtual string CustomerLookup
{
get
{
return this._CustomerLookup;
}
set
{
this._CustomerLookup = value;
}
}
#endregion
I would have thought providing the DescriptionField would take care of this, but it does not.
Before answering the question, let me first mention 2 major issues with the code snippet above:
In Acumatica Customers is one the specific system object types, that supports segmented keys. To create a look up for records, that support segmented keys, you should be using the PXDimensionSelectorAttribute instead of the PXSelectorAttribute. For Customer entity there are several attributes provided out of the box, like the CustomerAttribute or the CustomerActiveAttribute, that you can use to create Customer lookups:
CustomerLookup field must be of the Int32? (int?) type: in Acumatica users can change Customer ID with time (via the Change ID button on the Customers screen). To establish a foreign key for the Customer DAC, the better approach is to declare an integer field and associate your custom record with Customers though the Customer.BAccount field
Below is the recommended declaration of a DAC field, that creates Customer lookup in UI:
[Serializable]
public partial class DetailsResult : IBqlTable
{
...
#region CustomerId
public abstract class customerId : PX.Data.IBqlField
{
}
[Customer(DescriptionField = typeof(Customer.acctName))]
public virtual Int32? CustomerID { get; set; }
#endregion
...
}
With the DescriptionField property specified, PXDimensionSelector placed on a form will by default format selected record according to the "{SearchKey/SubstituteKey} - {DescriptionField}" pattern:
To show DescriptionField in a grid cell, you have to define additional column for the CustomerID_description field (where _description part is a special key word for Acumatica used specifically in this type of requests):
I believe the answer is one that's obvious - I don't think the description field works the same way in the grid. In a header field, it works to show the CD - Description when you navigate off of it. Grid fields apparently don't work that way, even when you specify the description field in the selector the way you would in a header selector.

Resources