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") { }
}
}
Related
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
}
I have a Rich Text field attached to the PMQuote and CRQuote DACs. On the CRQuote, the user field is on the standalone class and the regular class, and that is working as desired. However, Acumatica's reporting does not show the HTML formatting so I am creating an unbound Plain Text field to put on the reports and in GI's. This field works fine on the PMQuote, but not on the CRQuote. On the CRQuote, the field is there, but it is always blank. I'm sure it is something to do with the projection, but I'm not sure how it should be created.
Here is the PMQuote field (working properly)
[PXString(IsUnicode = true)]
[PXUIField(Visible = false, DisplayName = "Scope Text")]
public virtual String UsrScopePlainText
{
get
{
return PX.Data.Search.SearchService.Html2PlainText(UsrScope);
}
}
public abstract class usrScopePlainText : PX.Data.BQL.BqlString.Field<usrScopePlainText> { }
And here is what I have on the CRQuote (not working):
public class CRQuoteExt : PXCacheExtension<CRQuote>
{
#region UsrScope
[PXDBText(IsUnicode = true, BqlField = typeof(CRQuoteStandaloneExt.usrScope))]
[PXUIField(DisplayName = "Scope")]
public virtual string UsrScope { get; set; }
public abstract class usrScope : IBqlField { }
#endregion
#region UsrScopePlainText
[PXString(IsUnicode = true)]
[PXUIField(Visible = false, DisplayName = "Scope Text")]
public virtual String UsrScopePlainText
{
get
{
return PX.Data.Search.SearchService.Html2PlainText(UsrScope);
}
}
public abstract class usrScopePlainText : IBqlField { }
#endregion
}
public class CRQuoteStandaloneExt : PXCacheExtension<PX.Objects.CR.Standalone.CRQuote>
{
#region UsrScope
[PXDBText(IsUnicode = true)]
[PXUIField(DisplayName = "Scope")]
public virtual string UsrScope { get; set; }
public abstract class usrScope : IBqlField { }
#endregion
#region UsrScopePlainText
[PXString(IsUnicode = true)]
[PXUIField(Visible = false, DisplayName = "Scope Text")]
public virtual String UsrScopePlainText
{
get
{
return PX.Data.Search.SearchService.Html2PlainText(UsrScope);
}
}
public abstract class usrScopePlainText : IBqlField { }
#endregion
}
Thanks!
An alternative solution could be to have a reusable attribute that you can attach to any field. I think this is cleaner than adding logic directly in the Data Access class...
using PX.Objects.IN;
using PX.Data;
using System;
namespace PX.Objects.IN
{
public class InventoryItemPlainTextBodyExt : InventoryItem
{
[HtmlToText(typeof(InventoryItem.body))]
[PXDependsOnFields(typeof(InventoryItem.body))]
[PXUIField(DisplayName="Body (Plain Text)")]
public virtual string BodyPlainText { get; set; }
public abstract class bodyPlainText : PX.Data.BQL.BqlString.Field<bodyPlainText> { }
}
[PXString]
public class HtmlToTextAttribute : PXEventSubscriberAttribute, IPXFieldSelectingSubscriber
{
protected Type _htmlField;
public HtmlToTextAttribute(Type htmlField) :base()
{
_htmlField = htmlField;
}
public void FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
e.ReturnValue = PX.Data.Search.SearchService.Html2PlainText(sender.GetValue(e.Row, _htmlField.Name) as string);
}
}
}
I'm not sure what happened, but I put the original code I posted above back into the customization project and it started working as expected.
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
}
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)]
I'm a bit lost here on what approach to take to get an aggregate value from my usr field on SOLineExt. My goal is a simple aggregation of the user field which is based on a this value from the SOLine:
itemExt.UsrMinutes * (int)row.OrderQty;
In the SOLineExt the value above is stored in UsrMultByQuant it gets the value fine but I can't seem to aggregate the the SOLineExt value to get the total of the UsrMultByQuant into my SOOrder field called UsrTotalWorkMinutes
[PXDBInt]
[PXUIField(DisplayName="TotalWorkMinutes")]
[PXFormula(null, typeof(SumCalc<SOLineExt.usrMultByQuant>))]
public virtual int? UsrTotalWorkMinutes{get;set;}
public abstract class usrTotalWorkMinutes : IBqlField{}
I was referencing T200 Lesson 7, also I attempted to implement a fieldselecting (as instructed on Lesson 11.8 in t300) to try that approach for getting my total usr field value from the SOLineExt table with no success.
Any advice is appreciated, Thank you
Edit:
I removed the null from the PXformula and i am receiving this error now.
I also modified the dac slightly to have the PXParent attribute to select the current SOLine
[PXDBInt]
[PXUIField(DisplayName="TotalWorkMinutes")]
[PXFormula(typeof(SumCalc<SOLineExt.usrMultByQuant>))]
[PXParent(typeof(Select<SOLine,
Where<SOLine.orderNbr, Equal<Current<SOOrder.orderNbr>>>>))]
public virtual int? UsrCuryWorkMinutes{get;set;}
public abstract class usrCuryWorkMinutes : IBqlField{}
Still does not total my SOLineExt value and I am recieving the error above when null removed.
The 2 extension classes from below should be enough to achieve the requested behavior (notice, fields UsrCuryWorkMinutes and UsrMultByQuant are of the decimal type):
public class SOOrderExt : PXCacheExtension<SOOrder>
{
public abstract class usrCuryWorkMinutes : IBqlField { }
[PXDBDecimal(2)]
[PXUIField(DisplayName = "Total Work Minutes")]
public virtual decimal? UsrCuryWorkMinutes { get; set; }
}
public class SOLineExt : PXCacheExtension<SOLine>
{
public abstract class usrMinutes : IBqlField { }
[PXDBInt]
[PXUIField(DisplayName = "Work Minutes")]
public virtual int? UsrMinutes { get; set; }
public abstract class usrMultByQuant : IBqlField { }
[PXDBDecimal(2)]
[PXUIField(DisplayName = "Total Work Minutes", Enabled = false)]
[PXFormula(typeof(Mult<IsNull<SOLine.orderQty, decimal0>, SOLineExt.usrMinutes>),
typeof(SumCalc<SOOrderExt.usrCuryWorkMinutes>))]
public virtual decimal? UsrMultByQuant { get; set; }
}
There is no need for PXParentAttribute in SOLineExt because of the original SOLine.OrderNbr field already decorated with PXParentAttribute to aggregated other values from SOLine to SOOrder:
[System.SerializableAttribute()]
[PXCacheName(Messages.SOLine)]
public partial class SOLine : PX.Data.IBqlTable, ILSPrimary, IDiscountable, ISortOrder
{
...
#region OrderNbr
public abstract class orderNbr : PX.Data.IBqlField
{
}
protected String _OrderNbr;
[PXDBString(15, IsUnicode = true, IsKey = true, InputMask = "")]
[PXDBDefault(typeof(SOOrder.orderNbr), DefaultForUpdate = false)]
[PXParent(typeof(Select<SOOrder, Where<SOOrder.orderType, Equal<Current<SOLine.orderType>>, And<SOOrder.orderNbr, Equal<Current<SOLine.orderNbr>>>>>))]
[PXUIField(DisplayName = "Order Nbr.", Visible = false, Enabled = false)]
public virtual String OrderNbr
{
...
}
#endregion
...
}