how to add a field on the Project Quotes screen PQ000025 - acumatica

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
}

Related

Add a column to a dac with langage

I would like to add the column "Description Family" taking into account the language of the connected user. I try the function "PXLocalizableDefault", But I don't know how to use this function.
public class InventoryItemExt : PXCacheExtension<PX.Objects.IN.InventoryItem>
{
#region UsrDescription
[PXUIField(DisplayName="Famille description")]
[PXLocalizableDefault(typeof(Search<INItemClass.descr,
Where<INItemClass.itemClassID,
Equal<InventoryItem.itemClassID>>>),typeof(User.languageName????)
,PersistingCheck=PXPersistingCheck.Nothing)]
#endregion
}
Description screen:
I believe you can use PXDBLocalizableString as a replacement for PXDBString and it will provide the functionality you are looking for.
public class InventoryItemExt : PXCacheExtension<PX.Objects.IN.InventoryItem>
{
#region UsrDescription
[PXUIField(DisplayName="Famille description")]
[PXDBLocalizableString(15, IsUnicode = true)]
public string UsrDescription { get; set; }
public class usrDescription : BqlString.Field<usrDescription > {}
#endregion
}

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.

How to add a AutoGenerate riwnumber as Key column in PXProjection?

I want to add a AutoGenerate number column in PXProjection DAC?
What i want,
In PXProjection DAC, I wan to add a Field, which should generate a unique number for each row, It might be unique with the combinaion of Fields consider in Projection, How may i do it?
Since I'm not sure how well you understand projections, let me cover some basics as I understand them first. A PXProjection is the xRP Framework equivalent of a SQL view. It does not contain any actual database tables or fields but simply creates access to a "view" into the data. As such, it does not have the ability to have a sequence, or identity, field of its own. It does, however, require that you define the key field(s). Once defined, you would retrieve the records of the projection as if it was its own table using reference to all of those key fields.
Here is a sample (not all fields) of one of my projections.
[PXProjection(typeof(
SelectFrom<INTran>
.LeftJoin<INLocation>
.On<INLocation.locationID.IsEqual<INTran.locationID>>
.LeftJoin<SOShipLine>
.On<SOShipLine.shipmentNbr.IsEqual<INTran.sOShipmentNbr>
.And<SOShipLine.lineNbr.IsEqual<INTran.sOShipmentLineNbr>>>
.LeftJoin<SOLine>
.On<SOLine.orderNbr.IsEqual<SOShipLine.origOrderNbr>
.And<SOLine.orderType.IsEqual<SOShipLine.origOrderType>
.And<SOLine.lineNbr.IsEqual<SOShipLine.origLineNbr>>>>
.LeftJoin<SOOrder>
.On<SOOrder.orderNbr.IsEqual<SOShipLine.origOrderNbr>
.And<SOOrder.orderType.IsEqual<SOShipLine.origOrderType>>>
.LeftJoin<ContactBAccount>
.On<ContactBAccount.bAccountID.IsEqual<SOOrder.billContactID>>
.LeftJoin<POReceiptLine>
.On<POReceiptLine.receiptNbr.IsEqual<INTran.pOReceiptNbr>
.And<POReceiptLine.lineNbr.IsEqual<INTran.pOReceiptLineNbr>>>
.LeftJoin<POOrder>
.On<POOrder.orderNbr.IsEqual<POReceiptLine.pONbr>
.And<POOrder.orderType.IsEqual<POReceiptLine.pOType>>>
))]
[Serializable]
[PXCacheName("Transactions Projection")]
public partial class MYINTransactions : IBqlTable
{
#region DocType
public abstract class docType : PX.Data.BQL.BqlString.Field<docType> { }
[PXDBString(1, IsFixed = true, IsKey = true, BqlField = typeof(INTran.docType))]
[PXUIField(DisplayName = INRegister.docType.DisplayName)]
public virtual String DocType { get; set; }
#endregion
#region TranType
public abstract class tranType : PX.Data.BQL.BqlString.Field<tranType> { }
[PXDBString(3, IsFixed = true, BqlField = typeof(INTran.tranType))]
[INTranType.List()]
[PXUIField(DisplayName = "Tran. Type")]
public virtual String TranType { get; set; }
#endregion
#region RefNbr
public abstract class refNbr : PX.Data.BQL.BqlString.Field<refNbr> { }
[PXDBString(15, IsUnicode = true, IsKey = true, BqlField = typeof(INTran.refNbr))]
[PXUIField(DisplayName = INRegister.refNbr.DisplayName)]
public virtual String RefNbr { get; set; }
#endregion
#region LineNbr
public abstract class lineNbr : PX.Data.BQL.BqlInt.Field<lineNbr> { }
[PXDBInt(IsKey = true, BqlField = typeof(INTran.lineNbr))]
[PXUIField(DisplayName = "Line Number")]
public virtual Int32? LineNbr { get; set; }
#endregion
#region TranDate
public abstract class tranDate : PX.Data.BQL.BqlDateTime.Field<tranDate> { }
[PXDBDate(BqlField = typeof(INTran.tranDate))]
public virtual DateTime? TranDate { get; set; }
#endregion
#region InvtMult
public abstract class invtMult : PX.Data.BQL.BqlShort.Field<invtMult> { }
[PXDBShort(BqlField = typeof(INTran.invtMult))]
[PXUIField(DisplayName = "Multiplier")]
public virtual Int16? InvtMult { get; set; }
#endregion
#region BranchID
public abstract class branchID : PX.Data.BQL.BqlInt.Field<branchID> { }
[Branch(typeof(INTran.branchID), BqlField = typeof(INTran.branchID))]
public virtual Int32? BranchID { get; set; }
#endregion
#region InventoryID
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
[PXDBInt(BqlField = typeof(INTran.inventoryID))]
public virtual Int32? InventoryID { get; set; }
#endregion
#region SubItemID
public abstract class subItemID : PX.Data.BQL.BqlInt.Field<subItemID> { }
[PXDBInt(BqlField = typeof(INTran.subItemID))]
public virtual Int32? SubItemID { get; set; }
#endregion
}
As you can see, it pulls data from many tables and then defines fields to be accessed via MYINTransactions and includes IsKey on the key fields and "BqlField =" to map to the related fields. Even though we use PXDB for the field attributes, these are not actual DB fields themselves. The PXProjectionAttribute overrides the behavior of the fields. I believe it is possible to set properties that will enable the projection to maintain data, at which point, the PXDB type attributes should convey the applicability to the database when the SQL commands are built from BQL. That's more advanced than I have had time to explore myself, so I won't go into any further detail there.
Now, more specifically to your question directly... Depending on how you intend to use the projection, you might define additional fields using PXDBScalar or PXFormula to populate the values, but in my attempts, this had unreliable results. The issue for me was that I needed the values at the time of the actual SQL call, and the fields, being unbound, did not exist at the database level. They would work on my screen, but some of my more complex BQL statements would fail because the values at the time of the SQL call were null due to being unbound.
The best recommendation that I can make is that you use a database field in one of the base DAC's to produce the desired field and map a field in your projection to that field. This will produce the most reliable results, should you try to use the projection in complex ways. Alternatively, if this is for use in a GI, you can use a formula in the GI's field definition to concatenate fields, if that is your goal.

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

Inserted Records in Cache on Graph Extension Not Saving to Database

I have an extension graph onto INReceiptEntry. I set up a view for the custom DAC that I want a cache generated for that will get objects inserted into. After I generate one of the objects I want to insert into the cache, I use ViewName.Insert(Object); (also used ViewName.Cache.Insert(Object) with same results) within the graph extension's RowPersisting handler. This normally would store the data items in the corresponding database data table associated to the DAC, but nothing is stored in the DB. Instead of If statement fires and I get a popup stating that the object wasn't inserted. Here is my code:
public class INReceiptEntry_Extension : PXGraphExtension<INReceiptEntry>
{
public PXSelect<EMPWorkOrderINRegister> WorkOrderINRegisters;
#region Event Handlers
protected void INRegister_RowPersisting(PXCache cache, PXRowPersistingEventArgs e)
{
var row = (INRegister)e.Row;
var rowExt = PXCache<INRegister>.GetExtension<INRegisterExt>(row);
//Get Target Objects
foreach (INTranSplit split in PXSelect<INTranSplit, Where<INTranSplit.refNbr,
Equal<Required<INRegister.refNbr>>, And<INTranSplit.tranType, Equal<TranType>>>>
.Select(Base, Base.CurrentDocument.Current.RefNbr))
{
EMPWorkOrderINRegister WOINR = new EMPWorkOrderINRegister();
WOINR.Woid = rowExt.Usrwoid;
WOINR.RefNbr = split.RefNbr;
WOINR.SplitLineNbr = split.SplitLineNbr;
if (WorkOrderINRegisters.Insert(WOINR) == null)
{
Base.CurrentDocument.Ask("Did not insert WOINR:" + WOINR.RefNbr.ToString() + ", " + WOINR.SplitLineNbr.ToString(), MessageButtons.OK);
return;
}
}
}
#endregion
}
Any reason this isn't inserting into the custom cache? Does using a graph extension or executing this cache insert in a Persisting function have anything to do with why this is failing?
By request, the DAC:
using System;
using PX.Data;
using PX.Objects.IN;
namespace Manufacturing
{
[Serializable]
public class EMPWorkOrderINRegister : IBqlTable
{
#region Id
[PXDBIdentity()]
[PXUIField(DisplayName = "Id")]
public int? Id { get; set; }
public class id : IBqlField { }
#endregion
#region Woid
[PXDBInt()]
[PXUIField(DisplayName = "Woid")]
public int? Woid { get; set; }
public class woid : IBqlField { }
#endregion
#region RefNbr
[PXDBString(15, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Receipt Number")]
public string RefNbr { get; set; }
public class refNbr : IBqlField { }
#endregion
#region SplitLineNbr
[PXDBInt()]
[PXUIField(DisplayName = "Split Line Nbr")]
public int? SplitLineNbr { get; set; }
public class splitLineNbr : IBqlField { }
#endregion
#region AvailableSNs
[PXString()]
[PXUIField(DisplayName = "Available SNs")]
public string AvailableSNs { get; set; }
public class availableSNs : IBqlField { }
#endregion
[PXString()]
[PXDBScalar(typeof(Search<INTranSplit.lotSerialNbr, Where<INTranSplit.refNbr, Equal<EMPWorkOrderINRegister.refNbr>,
And<INTranSplit.splitLineNbr, Equal<EMPWorkOrderINRegister.splitLineNbr>>>>))]
public string SelectedSN { get; set; }
public class selectedSN : IBqlField { }
}
}
Eric, there is one major issue with your DAC, which is the lack of key fields.
Additional area of improvement in the INRegister_RowPersisting handler. RowPersisting handlers are designed to either validate the data record before it's committed to database or cancel the commit operation of a specific data record. For more details, please refer to the Acumatica Framework API Reference
The better approach for your scenario is to override the Persist method and insert missing EMPWorkOrderINRegister records before execution of the base Persist method. It's also a good idea to use a try-catch statement and delete EMPWorkOrderINRegister records with the Inserted status if base Persist method had failed.

Resources