I have created a Name value pair field for Sales Order table and Search is giving error while using the field from Description field in selector
#region UsrLoader
public abstract class usrLoader : IBqlField { }
[PXDBString(128, IsUnicode = true)]
[PXUIField(DisplayName = "Operator 1")]
[PXSelector(typeof(EPEmployee.acctCD),
new Type[]
{
typeof(EPEmployee.acctCD),
typeof(EPEmployee.acctName)
},
DescriptionField = typeof(EPEmployee.acctName))]
public virtual string UsrLoader { get; set; }
#endregion
#region UsrUnLoader
[PXDBString(128)]
[PXUIField(DisplayName = "Operator 2")]
[PXSelector(typeof(EPEmployee.acctCD),
new Type[]
{
typeof(EPEmployee.acctCD),
typeof(EPEmployee.acctName)
},
DescriptionField = typeof(EPEmployee.acctName))]
public virtual string UsrUnLoader { get; set; }
public abstract class usrUnLoader : IBqlField { }
#endregion
I am getting the following error
Typically I see the Invalid column error when the customization hasn't been published to insert the field in the database table. Did you publish after adding the fields?
Also, the warnings might tell you to join in the parent table. Did you try doing a join to the EPEmployee table to use the description/name field in your GI?
Related
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.
I created a selector control which displays a list of all serial #s from INItemLotSerial table, it works fine, the problem is the description field is showing InventoryID, how to show InventoryCD. Please have a look at below sample code.
[PXSelector(typeof(Search<INItemLotSerial.lotSerialNbr>),
new Type[] { typeof(INItemLotSerial.lotSerialNbr), typeof(INItemLotSerial.inventoryID) },
SubstituteKey = typeof(INItemLotSerial.lotSerialNbr), DescriptionField = typeof(INItemLotSerial.inventoryID))]
// i also joined with InventoryItem but this doesn't works.
[PXSelector(typeof(Search2<INItemLotSerial.lotSerialNbr,
LeftJoinSingleTable<InventoryItem, On<InventoryItem.inventoryID,Equal<INItemLotSerial.inventoryID>>>>),
new Type[] { typeof(INItemLotSerial.lotSerialNbr), typeof(INItemLotSerial.inventoryID) },
SubstituteKey = typeof(INItemLotSerial.lotSerialNbr), DescriptionField = typeof(InventoryItem.inventoryCD))]
The main problem with DescriptionField property is that it is waiting for getting the field from the same table for which Selector is written. But in the case of ID/CD usually, the CD is not present in the table where ID is present, except the main table.
UPDATED I have removed previous code (implementation using custom attributes and FieldSelecting event handler) because of the performance issues which it is bringing with it. The code below is resulting with the same lookup but getting the data with one inner join instead of all the requests which the previous code was doing.
You can do the following to get this lookup with description:
Create a PXProjection on INItemLotSerial and InventoryItem tables like below:
[PXCacheName("Lot Serials with Inventory CD")]
[PXProjection(typeof(Select2<INItemLotSerial,
InnerJoin<InventoryItem,
On<INItemLotSerial.inventoryID, Equal<InventoryItem.inventoryID>>>>))]
public class INItemLotSerialWithInventoryItem : IBqlTable
{
[PXDBInt(BqlField = typeof(INItemLotSerial.inventoryID))]
[PXUIField(DisplayName = "Inventory ID", Visibility = PXUIVisibility.Visible, Visible = false)]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : IBqlField { }
[PXDBString(InputMask = "", IsUnicode = true, BqlField = typeof(InventoryItem.inventoryCD))]
[PXUIField(DisplayName = "Inventory ID")]
public virtual string InventoryCD { get; set; }
public abstract class inventoryCD : IBqlField { }
[PXDBString(InputMask = "", IsUnicode = true, BqlField = typeof(INItemLotSerial.lotSerialNbr))]
[PXUIField(DisplayName = "Lot/Serial Nbr")]
public virtual string LotSerialNbr { get; set; }
public abstract class lotSerialNbr : IBqlField { }
}
Set your selector to use this PXProjection like below:
[PXSelector(typeof(Search<INItemLotSerialWithInventoryItem.lotSerialNbr>),
new Type[] { typeof(INItemLotSerialWithInventoryItem.lotSerialNbr) },
SubstituteKey = typeof(INItemLotSerialWithInventoryItem.lotSerialNbr),
DescriptionField = typeof(INItemLotSerialWithInventoryItem.inventoryCD))]
As a result, you will get lookup like below:
I have created a custom DAC, Graph, and Screen to manage tracking of new entity for client, called "Management Company." New screen is simple Grid with CRUD controls. Selector on Customer screen allows me to choose from list of "Management Company" entries. I also added new field to Contact DAC and DB table to track which "Management Company" is assigned to a given contact. This field is where the selector is configured.
I am trying to enable the "AllowAddNew" and/or "AllowEdit" properties of this selector. When I set to "True," the buttons show up but they don't do anything.
I can create and save new entries to this DB table via the new screen and I can retrieve them with the Selector just fine. I just can't create new from selector.
I have tried looking this up and I'm not finding much information.
How can I achieve this?
Sample of DAC:
namespace PX.Objects.CR
{
[Serializable]
public class UsrCustomerManagementCompany : IBqlTable
{
#region MancompID
[PXDBString(16, IsUnicode = true, InputMask = ">LLLLLLLLLLLLLLLL", IsKey = true)]
[PXUIField(DisplayName = "Company ID")]
[PXDefault]
public virtual string MancompID { get; set; }
public abstract class mancompID : IBqlField { }
#endregion
#region MancompName
[PXDBString(60, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Company Name")]
[PXDefault]
public virtual string MancompName { get; set; }
public abstract class mancompName : IBqlField { }
#endregion
#region MancompDescr
[PXDBString(4000, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Description")]
public virtual string MancompDescr { get; set; }
public abstract class mancompDescr : IBqlField { }
#endregion
}
}
Graph:
using System;
using PX.Data;
using PX.Objects.CR;
namespace ClientCode
{
public class ManagementCompanyMaint : PXGraph<ManagementCompanyMaint, UsrCustomerManagementCompany>
{
public PXSelect<UsrCustomerManagementCompany> ManagementCompanies;
}
}
Contact DAC Extension and Selector:
namespace PX.Objects.CR
{
public class ContactExt : PXCacheExtension<PX.Objects.CR.Contact>
{
#region UsrManagementCompany
[PXDBString]
[PXUIField(DisplayName = "Management Company")]
[PXSelector(
typeof(Search<UsrCustomerManagementCompany.mancompID>),
new Type[]
{
typeof(UsrCustomerManagementCompany.mancompID),
typeof(UsrCustomerManagementCompany.mancompName)
},
SubstituteKey = typeof(UsrCustomerManagementCompany.mancompName)
)]
public virtual string UsrManagementCompany { get; set; }
public abstract class usrManagementCompany : IBqlField { }
#endregion
}
}
I think all you are missing is the PXPrimaryGraph attribute on your DAC to indicate for that record type what is the main graph to refer to.
In your case try adding...
[PXPrimaryGraph(typeof(ClientCode.ManagementCompanyMaint))]
[Serializable]
public class UsrCustomerManagementCompany : IBqlTable
{
//...
}
Here are some related questions that might also help:
How to create a hyperlink user field
how to use AllowEdit in Acumatica
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
...
}
I have a custom processing page. The main DAC of the data view is ARRegister, but there is the data view delegate. Both the view & delegate join ARCashSale & ARInvoice to the main DAC, The reason for this is...some records are cash sales, and others are invoices, overdue charges, ect. A few grid columns are included, which displays data specific to a cash sale. I invoke a static method in my process graph to assign the process delegate. The method runs with no errors.
In the data view delegate, I check the doc type for each record returned from the BQL.
If cash sale, then
yield return new PXResult<ARRegister, ARCashSale>(register, cashsale)
ELSE
yield return new PXResult<ARRegister>(register)
The reason for the delegate is to check some other conditions which cannot be determined using standard BQL. I notice the data in the column specific to a cash sale disappears after the user selects 'Process All'. I am unable to determine the reason. Checking to see if others have experienced this.
DataView
public PXProcessingJoin<ARRegister,
LeftJoin<cs.ARCashSale, On<ARRegister.docType, Equal<cs.ARCashSale.docType>, And<ARRegister.refNbr, Equal<cs.ARCashSale.refNbr>>>,
LeftJoin<ARInvoice, On<ARRegister.docType, Equal<ARInvoice.docType>, And<ARRegister.refNbr, Equal<ARInvoice.refNbr>>>,
InnerJoin<Customer,On<ARRegister.customerID,Equal<Customer.bAccountID>>>>>,
Where2<Where<ARRegister.released, Equal<True>, And<ARRegister.branchID, Equal<Current<AccessInfo.branchID>>>>,
And<Where<Customer.finChargeApply,Equal<True>>>>> Registers;
This is an older question, but I had a similar issue.
You need to add a boolean field named "Selected" to DACs you want to process.
The way I solved it was using a local DAC.
You can make it inherit from ARRegister and just add the required field.
In my case I used PXProjection, inherited from the main DAC and added the fields I needed from the joined DACs. Note that you need to add the BqlField = typeof(DAC.field) property to the type attribute of these fields to map them to the correct DAC.
Then in the PXProcessing view you just use your local DAC.
Also, it is very useful to try the Request Profiler screen (SM205070) when troubleshooting BQL.
Basically in processing screens sub DAC (other than Main DAC in view), filed values will not persist once the process completed.
In this case, the PXProjection will help us to persist the values even after completion of the process for the rows/records in processing screens.
Please find the sample Projection View and DAC below.
[PXProjection(typeof(Select2<SOShipment, InnerJoin<SOOrderShipment,
On<SOOrderShipment.shipmentNbr, Equal<SOShipment.shipmentNbr>,
And<SOShipment.status, Equal<SOShipmentStatus.confirmed>>>,
InnerJoin<SOOrder, On<SOOrderShipment.orderType, Equal<SOOrder.orderType>,
And<SOOrderShipment.orderNbr, Equal<SOOrder.orderNbr>>>>>>))]
Projection DAC:
[Serializable]
public class ProjectionShipmentDAC : IBqlTable
{
#region Selected
public abstract class selected : IBqlField
{
}
protected bool? _Selected = false;
[PXBool]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected
{
get
{
return _Selected;
}
set
{
_Selected = value;
}
}
#endregion
#region Status
[PXDBString(1, IsFixed = true, BqlField = typeof(SOShipment.status))]
[PXUIField(DisplayName = "Status")]
[SOShipmentStatus.List()]
public virtual string Status { get; set; }
public abstract class status : IBqlField { }
#endregion
#region ShipmentNbr
[PXDBString(15, IsKey = true, IsUnicode = true, BqlField = typeof(SOShipment.shipmentNbr))]
[PXUIField(DisplayName = "Shipment Nbr.")]
public virtual string ShipmentNbr { get; set; }
public abstract class shipmentNbr : IBqlField { }
#endregion
#region ShipDate
[PXDBDate(BqlField = typeof(SOShipment.shipDate))]
[PXUIField(DisplayName = "Shipment Date")]
public virtual DateTime? ShipDate { get; set; }
public abstract class shipDate : IBqlField { }
#endregion
#region CustomerID
[PXDBInt(BqlField = typeof(SOShipment.customerID))]
[PXUIField(DisplayName = "Customer")]
[PXSelector(typeof(Customer.bAccountID), new Type[] { typeof(Customer.acctCD), typeof(Customer.acctName) },
SubstituteKey = typeof(Customer.acctCD), DescriptionField = typeof(BAccount.acctName))]
public virtual int? CustomerID { get; set; }
public abstract class customerID : IBqlField { }
#endregion
#region Shipped Quantity
[PXDBDecimal(BqlField = typeof(SOShipment.shipmentQty))]
[PXUIField(DisplayName = "Shipped Quantity")]
public virtual decimal? ShipmentQty { get; set; }
public abstract class shipmentQty : IBqlField { }
#endregion
}
Have you played around with MatrixMode and/or SyncPosition on your page grid? You might need SyncPosition="True"
Also, does the issue occur if not using process all? (process 1 or 2 rows)