PXDBScalar SOOrderKvExt attribute bool - acumatica

I'm trying to use PXDBScalar to bring in a boolean attribute from the Sales Order user defined fields tab to the Shipment screen.
I found another stack overflow post that helped with the creation of the SOOrderKvExt DAC, and I am able to retrieve the value of the valueNumeric (decimal) field via my PXDBScalar attribute, but I cannot find a way to convert the value to a bool so it properly displays as a checkbox on the screen. I tried setting the data type for my unbound field to bool, but got a data type conversion error. I also tried leaving the field as a decimal and just changing the control type on the screen, but it always displays as checked regardless of the value. Any idea how I can convert the decimal value to a bool in the PXDBScalar attribute or another solution?
Code snippets provided below.
SOOrderKvExt
[PXCacheName("SO Order Attributes")]
[Serializable]
public class SOOrderKvExt : IBqlTable
{
public abstract class recordID : BqlGuid.Field<recordID> { }
[PXDBGuid(IsKey = true)]
public Guid? RecordID { get; set; }
public abstract class fieldName : BqlString.Field<fieldName> { }
[PXDBString(50,IsKey = true)]
[PXUIField(DisplayName ="Name")]
public string FieldName { get; set; }
public abstract class valueNumeric : BqlDecimal.Field<valueNumeric> { }
[PXDBDecimal(8)]
[PXUIField(DisplayName = "Value Numeric")]
public decimal? ValueNumeric { get; set; }
public abstract class valueDate : BqlDateTime.Field<valueDate> { }
[PXDBDate]
[PXUIField(DisplayName = "Value Date")]
public DateTime? ValueDate { get; set; }
public abstract class valueString : BqlString.Field<valueString> { }
[PXDBString(256)]
[PXUIField(DisplayName = "Value String")]
public string ValueString { get; set; }
public abstract class valueText : BqlString.Field<valueText> { }
[PXDBString]
[PXUIField(DisplayName = "Value Text")]
public string ValueText { get; set; }
}
}
PXDBScalar
#region UsrSOBlindShip
[PXDecimal(8)]
[PXUIField(DisplayName="SO Blind Ship", IsReadOnly=true)]
[PXDBScalar(typeof(Search2<SOOrderKvExt.valueNumeric,
LeftJoin<SOOrder, On<SOOrder.noteID, Equal<SOOrderKvExt.recordID>>,
LeftJoin<SOShipLine, On<SOShipLine.origOrderNbr, Equal<SOOrder.orderNbr>>>>,
Where<SOShipLine.shipmentNbr, Equal<SOShipment.shipmentNbr>>>))]
public virtual decimal? UsrSOBlindShip{ get; set; }
public abstract class usrSOBlindShip: PX.Data.BQL.BqlDecimal.Field<usrSOBlindShip> { }
#endregion
Thanks
Scott

I would add a boolean calculated field. Similar to this :
public class SOLineExt : PXCacheExtension<PX.Objects.SO.SOLine>
{
#region UsrIsZero
[PXBool]
[PXUIField(DisplayName="Is Zero")]
[PXFormula(typeof(Switch< Case<Where<SOLine.orderQty, Greater<decimal0>>, False>, True >))]
public virtual bool? UsrIsZero { get; set; }
public abstract class usrIsZero : PX.Data.BQL.BqlBool.Field<usrIsZero> { }
#endregion
}

Related

blank row being added on insert

I have a very simple Maint page, it has no events
public PXCancel<RCDistributorSalesStat> Cancel;
public PXSave<RCDistributorSalesStat> Save;
public SelectFrom<RCDistributorSalesStat>.View Records;
and everytime I save the first record entered I get an error and it has added a second blank line and throws errors that required fields are missing.
I found a similar question to this on here about having multiple ISKey set, though I only have one.
#region DistributorSalesStatID
[PXDBIdentity(IsKey = true)]
public virtual int? DistributorSalesStatID { get; set; }
public abstract class distributorSalesStatID : PX.Data.BQL.BqlInt.Field<distributorSalesStatID> { }
#endregion
#region InventoryID
[StockItem(Visibility = PXUIVisibility.SelectorVisible, DescriptionField = typeof(InventoryItem.inventoryCD), Enabled = true)]
[PXRestrictor(typeof(Where<InventoryItem.baseUnit.IsEqual<BQLConstants.Straw>>), null)]
[PXForeignReference(typeof(Field<inventoryID>.IsRelatedTo<InventoryItem.inventoryID>))]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
#endregion
#region StatisticDate
[PXDBDate()]
[PXUIField(DisplayName = "Statistic Date")]
public virtual DateTime? StatisticDate { get; set; }
public abstract class statisticDate : PX.Data.BQL.BqlDateTime.Field<statisticDate> { }
#endregion
#region CustomerID
[CustomerActive(
//typeof(Search<BAccountR.bAccountID, Where<True, Equal<True>>>),
Visibility = PXUIVisibility.SelectorVisible,
DescriptionField = typeof(Customer.acctName),
Filterable = true) ]
//[CustomerOrOrganizationInNoUpdateDocRestrictor]
[PXForeignReference(typeof(Field<RCDistributorSalesStat.customerID>.IsRelatedTo<PXAccess.BAccount.bAccountID>))]
public virtual int? CustomerID { get; set; }
public abstract class customerID : PX.Data.BQL.BqlInt.Field<customerID> { }
#endregion
#region CustomerLocationID
[LocationActive(typeof(Where<Location.bAccountID, Equal<Current<customerID>>,
And<MatchWithBranch<Location.cBranchID>>>),
DescriptionField = typeof(Location.descr),
Visibility = PXUIVisibility.SelectorVisible)]
[PXDefault(typeof(Coalesce<Search2<BAccountR.defLocationID,
InnerJoin<CRLocation, On<CRLocation.bAccountID, Equal<BAccountR.bAccountID>, And<CRLocation.locationID, Equal<BAccountR.defLocationID>>>>,
Where<BAccountR.bAccountID, Equal<Current<customerID>>,
And<CRLocation.isActive, Equal<True>,
And<MatchWithBranch<CRLocation.cBranchID>>>>>,
Search<CRLocation.locationID,
Where<CRLocation.bAccountID, Equal<Current<customerID>>,
And<CRLocation.isActive, Equal<True>, And<MatchWithBranch<CRLocation.cBranchID>>>>>>))]
[PXForeignReference(
typeof(CompositeKey<
Field<customerID>.IsRelatedTo<Location.bAccountID>,
Field<customerLocationID>.IsRelatedTo<Location.locationID>
>))]
public virtual int? CustomerLocationID { get; set; }
public abstract class customerLocationID : PX.Data.BQL.BqlInt.Field<customerLocationID> { }
#endregion
#region SalesAmount
[PXDBDecimal()]
[PXUIField(DisplayName = "Sales Amount")]
public virtual Decimal? SalesAmount { get; set; }
public abstract class salesAmount : PX.Data.BQL.BqlDecimal.Field<salesAmount> { }
#endregion
#region SalesUnits
[PXDBInt()]
[PXUIField(DisplayName = "Sales Units")]
public virtual int? SalesUnits { get; set; }
public abstract class salesUnits : PX.Data.BQL.BqlInt.Field<salesUnits> { }
#endregion
#region QuantityOnHand
[PXDBInt()]
[PXUIField(DisplayName = "Quantity On Hand")]
public virtual int? QuantityOnHand { get; set; }
public abstract class quantityOnHand : PX.Data.BQL.BqlInt.Field<quantityOnHand> { }
#endregion
I am unsure what is causing the unwanted row to try and persist.
I have changed my keys around, I removed my IsKey on the PXDBIdentity and set two other fields as the key in the DAC and the DB. That seems to have the desired effect as no blank row gets created during Save. Upon further testing it appears that for our listview page I was missing "px:Selector" rows inside of my RowTemplate in my Grid.

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 do I enable custom attributes? (can assign on class, but not displaying for transaction)

I defined several new screens in Acumatica 2018R2 and need to enable attribute support according the class assigned to the transaction. The class screen appears to allow attaching attributes, but the transactional screen does not display any attribute. I found several examples on Stack Overflow, but the only clue I see seems to be that if the class id cannot be determined then no attributes will show. However, upon debug, I see that the class id is found.
This is my test code where I have tried stripping down to a very basic test.
AAClass
using PX.Data;
using System;
namespace Attributes
{
[Serializable]
public class AAClass : IBqlTable
{
#region ClassID
[PXDBIdentity]
[PXUIField(DisplayName = "Class ID")]
public virtual int? ClassID { get; set; }
public abstract class classID : IBqlField { }
#endregion
#region ClassCD
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Class CD")]
public virtual string ClassCD { get; set; }
public abstract class classCD : IBqlField { }
#endregion
#region Descr
[PXDBString(256, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Descr")]
public virtual string Descr { get; set; }
public abstract class descr : IBqlField { }
#endregion
#region CreatedByID
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
public abstract class createdByID : IBqlField { }
#endregion
#region CreatedByScreenID
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
public abstract class createdByScreenID : IBqlField { }
#endregion
#region CreatedDateTime
[PXDBCreatedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldCreatedDateTime)]
public virtual DateTime? CreatedDateTime { get; set; }
public abstract class createdDateTime : IBqlField { }
#endregion
#region LastModifiedByID
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
public abstract class lastModifiedByID : IBqlField { }
#endregion
#region LastModifiedByScreenID
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
public abstract class lastModifiedByScreenID : IBqlField { }
#endregion
#region LastModifiedDateTime
[PXDBLastModifiedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldLastModifiedDateTime)]
public virtual DateTime? LastModifiedDateTime { get; set; }
public abstract class lastModifiedDateTime : IBqlField { }
#endregion
#region Tstamp
[PXDBTimestamp()]
public virtual byte[] Tstamp { get; set; }
public abstract class tstamp : IBqlField { }
#endregion
#region NoteID
[PXNote]
public virtual Guid? NoteID { get; set; }
public abstract class noteID : IBqlField { }
#endregion
}
}
AAClassMaint
using PX.Data;
using PX.Objects.CR;
namespace Attributes
{
public class AAClassMaint : PXGraph<AAClassMaint, AAClass>
{
#region Data Views
[PXViewName("Classes")]
public PXSelect<AAClass> Classes;
[PXViewName("Attributes")]
public CSAttributeGroupList<AAClass, AATag> Mapping;
#endregion
}
}
AATag
using PX.Data;
using PX.Objects.CR;
using PX.Objects.CS;
using System;
namespace Attributes
{
[Serializable]
public class AATag : IBqlTable
{
#region TagID
[PXDBIdentity]
public virtual int? TagID { get; set; }
public abstract class tagID : IBqlField { }
#endregion
#region TagCD
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Tag ID")]
public virtual string TagCD { get; set; }
public abstract class tagCD : IBqlField { }
#endregion
#region MyClassID
[PXDBInt()]
[PXSelector(
typeof(AAClass.classID),
typeof(AAClass.classCD),
typeof(AAClass.descr),
SubstituteKey = typeof(AAClass.classCD)
)]
[PXUIField(DisplayName = "My Class ID")]
public virtual int? MyClassID { get; set; }
public abstract class myClassID : IBqlField { }
#endregion
#region CreatedByID
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
public abstract class createdByID : IBqlField { }
#endregion
#region CreatedByScreenID
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
public abstract class createdByScreenID : IBqlField { }
#endregion
#region CreatedDateTime
[PXDBCreatedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldCreatedDateTime)]
public virtual DateTime? CreatedDateTime { get; set; }
public abstract class createdDateTime : IBqlField { }
#endregion
#region LastModifiedByID
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
public abstract class lastModifiedByID : IBqlField { }
#endregion
#region LastModifiedByScreenID
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
public abstract class lastModifiedByScreenID : IBqlField { }
#endregion
#region LastModifiedDateTime
[PXDBLastModifiedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldLastModifiedDateTime)]
public virtual DateTime? LastModifiedDateTime { get; set; }
public abstract class lastModifiedDateTime : IBqlField { }
#endregion
#region Tstamp
[PXDBTimestamp()]
public virtual byte[] Tstamp { get; set; }
public abstract class tstamp : IBqlField { }
#endregion
#region NoteID
[PXNote]
public virtual Guid? NoteID { get; set; }
public abstract class noteID : IBqlField { }
#endregion
#region Attributes
public abstract class attributes : IBqlField { }
[CRAttributesField(typeof(AATag.myClassID))]
public virtual string[] Attributes { get; set; }
public virtual int? ClassID
{
get { return MyClassID; }
}
#endregion
}
}
AATagEntry
using PX.Data;
using PX.Objects.CR;
namespace Attributes
{
public class AATagEntry : PXGraph<AATagEntry, AATag>
{
#region Data Views
[PXViewName("Classes")]
public PXSelect<AATag> Tags;
[PXViewName("Answers")]
public CRAttributeList<AATag> Answers;
#endregion
}
}
As I understand the various posts for this topic, the key requirements are:
Define MAPPING in the class maintenance screen
[PXViewName("Attributes")]
public CSAttributeGroupList<AAClass, AATag> Mapping;
Define ANSWERS in the transactional entry screen
[PXViewName("Answers")]
public CRAttributeList<AATag> Answers;
Include NoteID in the transactional table
Add ATTRIBUTES to the transactional table, including a field for ClassID
public abstract class attributes : IBqlField { }
[CRAttributesField(typeof(AATag.myClassID))]
public virtual string[] Attributes { get; set; }
public virtual int? ClassID
{
get { return MyClassID; }
}
CRAttributesField attribute will build a request with the generic type (classIdField) provided in it's parameter. In your case that would be AATag.myClassID :
protected static Type GetAttributesSearchCommand(Type classIdField)
{
var cmd = BqlCommand.Compose(typeof (Search2<,,>), typeof (CSAttribute.attributeID),
typeof (InnerJoin<,>), typeof (CSAttributeGroup),
typeof (On<,>), typeof (CSAttributeGroup.attributeID), typeof (Equal<>),
typeof (CSAttribute.attributeID),
typeof(Where<,,>), typeof(CSAttributeGroup.entityType), typeof(Equal<>), typeof(Required<>), typeof(CSAttributeGroup.entityType),
typeof (And<,>), typeof (CSAttributeGroup.entityClassID), typeof (Equal<>), typeof (Current<>),
classIdField);
return cmd;
}
So the key part of the request where clause will be:
And<CSAttributeGroup.entityClassID, Equal<Current<AATag.myClassID>>>
This means you must have a current AATag record in memory:
Caches[typeof(AATag)].Current
I suggest you first trace the value (Help->Trace window) to validate it's non null:
public void AATag_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
if (e.Row is AATag)
{
PXTrace.WriteInformation(((AATag)e.Row).myClassID);
}
}
If it is null, you will have to join AATag in the relevant DataView (preferred) or set it explicitely in some events.
Using Acumatica Request Profiler (SM205070
) can also help to determine why the request is not returning any record.
As HB_Acumatica suggested in the comments, the issue appeared to be with the ClassID fields being defined as integer.
I removed the original ClassID (int) fields and renamed the ClassCD (string) fields in the Class DAC's. Next, I changed the ClassID fields in the transactional DAC's to strings. Problem solved. The attribute tab on the transactional entry screens now display the attributes assigned to the class selected.
Lesson learned: A "Class" DAC should not have a ClassID/ClassCD pair, but rather a simple string ClassID field. (Typically named specific to the type of class, i.e. TagClassID) The Class ID used in the transactional tables will then use the string Class ID.

Why is my grid not saving more than one row?

I have a grid embedded in a popup that stores user selected items from another grid. The user highlights the desired row, clicks a button, and it is added as a new row in the grid based on the information of the highlighted row. For some reason, it is not adding a new row, but instead it is overwriting the current one:
Adding new row for the first time:
Trying to add second row:
The first image I selected to add a new row the first time. The second image shows that when I add a second row, it overwrites the current row instead of inserting a new row. I tried to do this whole process at first with a PXFilter and found that PXFilters only allow for one row to be stored. I then created a blank table of the same name as the filter with all of the fields, changed the view to PXSelect, and thought it might be that, but it didn't fix it.
The code for the Add to MTO button is:
public PXAction<PMProject> addToMTO;
[PXUIField(DisplayName = "Add to MTO")]
[PXButton]
protected virtual void AddToMTO()
{
SOSiteStatusSelected row = sitestatus.Current;
if (row == null)
return;
bool isMade = false;
//NOTE: If you have a more efficient method to check if a view contains a row, please include that in the answer.
foreach (MTOLSelected testLine in SelectedItems.Select())
{
if (testLine.ItemID == row.InventoryID)
{
isMade = true;
break;
}
}
if (!isMade)
{
MTOLSelected line = new MTOLSelected();
SelectedItems.Insert(line);
line.ItemID = row.InventoryID;
line.ItemCD = row.InventoryCD;
line.Price = row.CuryUnitPrice;
line.Descr = row.Descr;
SelectedItems.Update(line);
}
else
{
SelectedItems.Ask("This item is already moved into the MTO List", MessageButtons.OK);
}
}
The DAC is:
[Serializable]
public class MTOLSelected : IBqlTable
{
[PXDBIdentity]
[PXUIField(DisplayName = "MTOLID")]
public int? Id { get; set; }
public abstract class id : IBqlField { }
//Might more Drawing Number and Qty Required to this new table
#region ItemID
[PXDBInt()]
[PXUIField(DisplayName = "ID")]
public virtual int? ItemID { get; set; }
public abstract class itemID : IBqlField { }
#endregion
#region ItemCD
[PXDBString(15)]
[PXUIField(DisplayName = "Item CD")]
public virtual string ItemCD { get; set; }
public abstract class itemCD : IBqlField { }
#endregion
#region Descr
[PXDBString(255)]
[PXUIField(DisplayName = "Desc")]
public virtual string Descr { get; set; }
public abstract class descr : IBqlField { }
#endregion
#region Qty
[PXDBInt()]
[PXUIField(DisplayName = "Qty")]
public virtual int? Qty { get; set; }
public abstract class qty : IBqlField { }
#endregion
#region Price
[PXDBDecimal()]
[PXUIField(DisplayName = "Price")]
public virtual decimal? Price { get; set; }
public abstract class price : IBqlField { }
#endregion
#region Length
[PXDBDecimal()]
[PXUIField(DisplayName = "Length")]
public virtual decimal? Length { get; set; }
public abstract class length : IBqlField { }
#endregion
#region Feet
[PXDBInt()]
[PXUIField(DisplayName = "Feet")]
public virtual int? Feet { get; set; }
public abstract class feet : IBqlField { }
#endregion
#region Inches
[PXDBDecimal()]
[PXUIField(DisplayName = "Inches")]
public virtual decimal? Inches { get; set; }
public abstract class inches : IBqlField { }
#endregion
}
Your DAC appears to need IsKey on the Identity field: [PXDBIdentity(IsKey=true)]

Acumatica - PXDBScalar uniqueidentifier is incompatible with int

I'm trying to populate this field with the value of a customer attribute.
public class CustomerExt : PXCacheExtension<Customer>
{
#region OtherID
[PXString]
[PXUIField(DisplayName = "Other ID")]
[PXDBScalar(typeof(Search<CSAnswers.value,
Where<CSAnswers.refNoteID, Equal<Current<Customer.noteID>>,
And<CSAnswers.attributeID, Like<OtherIDAttr>>>>))]
public virtual string UsrOtherID { get; set; }
public abstract class usrOtherID : IBqlField { }
#endregion
public class OtherIDAttr: Constant<string>
{
public OtherIDAttr() : base("OTHERID") { }
}
}
It causes the above error when the field is added to a screen. If I remove the second condition from the Search<>, the field populates, so I'm sure its the comparison between the CSAnswers AttributeID and the constant string.
If someone could point me in the right direction, that would be awesome.
Looks like you get this error due to the Current operator (Equal<Current<Customer.noteID>>) used within PXDBScalarAttribute.
Attempt to simply remove the Current operator led to a different error Invalid column name 'NoteID'., which can be resolved by the replacement of Customer.noteID with PX.Objects.CR.BAccount.noteID:
public class CustomerExt : PXCacheExtension<Customer>
{
#region OtherID
public abstract class usrOtherID : IBqlField { }
[PXString]
[PXUIField(DisplayName = "Other ID")]
[PXDBScalar(typeof(Search<CSAnswers.value,
Where<CSAnswers.refNoteID, Equal<BAccount.noteID>,
And<CSAnswers.attributeID, Like<OtherIDAttr>>>>))]
public virtual string UsrOtherID { get; set; }
#endregion
public class OtherIDAttr : Constant<string>
{
public OtherIDAttr() : base("OTHERID") { }
}
}

Resources