I am trying to lookup all records in a table where an id equals a variable and the order number equals another variable. When the order number variable is blank or null, I don't get any records even though there are matches in the database.
var chkExcepts = new PXSelect<EDImportExcept,
Where<EDImportExcept.eDIRefNbr, Equal<Required<EDImportExcept.eDIRefNbr>>,
And<Where<EDImportExcept.orderNbr, Equal<Required<EDImportExcept.orderNbr>>,
And<Where<EDImportExcept.active, Equal<Required<EDImportExcept.active>>>>>>>>(this);
PXResultset<EDImportExcept> excepts =
chkExcepts.Select(strDocumentId, ediOrder.OrderNbr ?? "", true);
The database column is set as nullable.
The DAC entry is defined as string:
#region OrderNbr
public abstract class orderNbr : PX.Data.IBqlField
{
}
protected string _OrderNbr;
[PXDBString(15, IsUnicode = true)]
[PXUIField(DisplayName = "Order Nbr")]
public virtual string OrderNbr
{
get
{
return this._OrderNbr;
}
set
{
this._OrderNbr = value;
}
}
#endregion
Why aren't the rows with the matching DocumentId and blank OrderNbr returned?
I moved the coalesce out of the select and set it to a variable and that seems to work. I was just trying to simplify the code.
Related
I'm trying to show a value calculated with PXFormula but the field doesn't show the value.
I have my CustomDAC named EDITran
public class EDITran : IBqlTable
{
#region Doctype
[PXDBString(50, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Doctype")]
[PXStringList
(new string[]
{"SO", "SHI", "INV" },
new string[]
{"Sales Order", "Shipment", "Invoice"}
)]
public virtual string Doctype { get; set; }
public abstract class doctype : PX.Data.BQL.BqlString.Field<doctype> { }
#endregion
#region Erprefnbr
[PXDBString(30, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "ERP RefNbr")]
public virtual string Erprefnbr { get; set; }
public abstract class erprefnbr : PX.Data.BQL.BqlString.Field<erprefnbr> { }
#endregion
#region Sync
[PXDBBool()]
[PXUIField(DisplayName = "Sync")]
public virtual bool? Sync { get; set; }
public abstract class sync : PX.Data.BQL.BqlBool.Field<sync> { }
#endregion
}
}
so I what to show the value of sync field on the Sales Order screen. The key is the ERP RefNbr (which would be SOOrder.OrderNbr)
I have added the custom non persisted field on the SOOrderExt DAC with this attributes
using PX.Objects.SO;
[PXBool]
[PXUIField(DisplayName="EDI Sync" , Enabled = false)]
[PXFormula(typeof(Selector<SOOrder.orderNbr,
Selector<EDITran.erprefnbr,
EDITran.sync>>))]
But when I added a record in EDITran and try to visualize it in SOOrder Form and I checked that EDITran.Sync = 1, it doesn't show the saved value.
Sales Order Screen
What I'm I doing wrong? Is the PXFormula correctly used?
PXFormula used incorrectly. PXFormula attribute works only with current DAC (which is SOOrder) or foreign DAC, existing in PXSelector join condition (you can use Selector keyword to get it).
For example, here is the SOOrder.OrderNbr selector declaration
[SO.RefNbr(typeof(Search2<SOOrder.orderNbr,
LeftJoinSingleTable<Customer, On<SOOrder.customerID, Equal<Customer.bAccountID>,
And<Where<Match<Customer, Current<AccessInfo.userName>>>>>>,
Where<SOOrder.orderType, Equal<Optional<SOOrder.orderType>>,
And<Where<Customer.bAccountID, IsNotNull,
Or<Exists<Select<SOOrderType,
Where<SOOrderType.orderType, Equal<SOOrder.orderType>,
And<SOOrderType.aRDocType, Equal<ARDocType.noUpdate>,
And<SOOrderType.behavior, Equal<SOBehavior.sO>>>>>>>>>>,
OrderBy<Desc<SOOrder.orderNbr>>>), Filterable = true)]
public virtual String OrderNbr
you can get some fields from the related Customer record, using Selector keyword
[PXFormula(typeof(Selector<
SOOrder.orderNbr,
Customer.consolidateStatements>))]
As a result, there are two possible solutions:
1) Rewrite SOOrder.OrderNbr selector declaration with your EDITran DAC
...
[SO.RefNbr(typeof(Search2<SOOrder.orderNbr,
LeftJoinSingleTable<Customer, On<SOOrder.customerID, Equal<Customer.bAccountID>,
And<Where<Match<Customer, Current<AccessInfo.userName>>>>>,
LeftJoin<EDITran, On<EDITran.doctype, Equal<SOOrder.orderType>,
And<EDITran.erprefnbr, Equal<SOOrder.orderNbr>>>>>,
Where<SOOrder.orderType, Equal<Optional<SOOrder.orderType>>,
And<Where<Customer.bAccountID, IsNotNull,
Or<Exists<Select<SOOrderType,
Where<SOOrderType.orderType, Equal<SOOrder.orderType>,
And<SOOrderType.aRDocType, Equal<ARDocType.noUpdate>,
And<SOOrderType.behavior, Equal<SOBehavior.sO>>>>>>>>>>,
OrderBy<Desc<SOOrder.orderNbr>>>), Filterable = true)]
public virtual String OrderNbr
Then it will be possible to get you field from there
[PXFormula(typeof(Selector<
SOOrder.orderNbr,
EDITran.sync>))]
2) Use PXDBScalar attribute to just get what you need. Note this will be a separate request to the database!!
...
[PXBool]
[PXDBScalar(typeof(Search<EDITran.sync,
Where<EDITran.doctype, Equal<SOOrder.orderType>,
And<EDITran.erprefnbr, Equal<SOOrder.orderNbr>>>>))]
public virtual bool? Sync
I'm not sure that's the right use of PXFormula. Here's the reference I normally use when I need to use PXFormula. See if it helps you simplify your PXFormula. You may need to simplify to a single Selector and define a foreign key to be able to complete your lookup.
Also, are you sure that the database contains the values that you expect? I often find that my problem is not where I think, and your issue may lie in setting the values or writing them to the database in your business logic.
It appears that you need the PXFormula to look to your EDITran table to find the record identified by the key (1st field specified in Selector) to then return back the value of the second field specified, which would reside in EDITran.
From Acumatica Developers Blog (AsiaBlog):
Selector
Selector does following:
Fetches a PXSelectorAttribute defined on the foreign key field (KeyField) of the current DAC.
Fetches the foreign data record currently referenced by the selector.
Using calculates and returns an expression on that data record as defined by ForeignOperand.
public class APVendorPrice : IBqlTable
{
// Inventory attribute is an aggregate containing a PXSelectorAttribute
// inside, which is also valid for Selector<>.
[Inventory(DisplayName = "Inventory ID")]
public virtual int? InventoryID
[PXFormula(typeof(Selector<
APVendorPrice.inventoryID,
InventoryItem.purchaseUnit>))]
public virtual string UOM { get; set; }
}
From that, I'd expect your PXFormula to look more like:
[PXFormula(typeof(Selector<
SOOrder.orderNbr,
EDITran.sync>))]
... assuming you have enough defined to tell Acumatica how to relate SOOrder.orderNbr to EDITran.erprefnbr.
The field that needs to save the record ID has an issue with resolving the autonumbering.
The DAC is set up to use autonumbering. However, when searching for a record or creating a new record, I get a 'The item AcctCD is not found (restricted:False,external:True,value: )' error
DAC:
[SerializableAttribute()]
[PXPrimaryGraph(typeof(LoanMaint))]
[PXCacheName("OLAccount")]
public class OLAccount : IBqlTable
{
[PXDBString(30, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXDefault()]
[PXUIField(DisplayName = "Loan Number", Visibility = PXUIVisibility.SelectorVisible, TabOrder = 1)]
[PXSelector(typeof(Search<OLAccount.acctCD>))]
[LoanAccount.RefNbr(typeof(Search2<OLAccount.acctCD,
InnerJoin<BAccountR, On<OLAccount.parentBAccountID, Equal<BAccountR.bAccountID>>>>),
Filterable = true, IsPrimaryViewCompatible = true)]
[LoanAccount.Numbering()]
public virtual string AcctCD { get; set; }
public abstract class acctCD : PX.Data.BQL.BqlString.Field<acctCD> { }
}
public class LoanAccount
{
/// <summary>
/// Specialized selector for OLAccount AcctCD.<br/>
/// By default, defines the following set of columns for the selector:<br/>
/// OLAccount.acctCD, OLAccount.acctName, OLAccount.externalAccountRef, <br/>
/// OLAccount.externalReference, OLAccount.parentBAccountID<br/>
/// </summary>
public class RefNbrAttribute : PXSelectorAttribute
{
public RefNbrAttribute(Type SearchType)
: base(SearchType,
typeof(OLAccount.acctCD),
typeof(OLAccount.acctName),
typeof(OLAccount.externalAccountRef),
typeof(OLAccount.parentBAccountID),
typeof(BAccountR.acctCD),
typeof(BAccountR.acctName),
typeof(BAccountR.type),
typeof(BAccountR.classID))
{
}
}
public class NumberingAttribute : AutoNumberAttribute
{
public NumberingAttribute()
: base(typeof(OLSetup.accountNumberingID), typeof(AccessInfo.businessDate)) { }
}
}
Graph:
public class LoanMaint : PXGraph<LoanMaint, OLAccount>
{
public PXSelect<OLAccount> LoanAccount;
public PXSelect<OLAccount, Where<OLAccount.acctCD, Equal<Current<OLAccount.acctCD>>>> CurrentLoanAccount;
public PXSetup<Company> Company;
public PXSetup<OLSetup> OLSetup;
public LoanMaint()
{
OLSetup setup = OLSetup.Current;
}
}
Error screen on system
I replicated this without receiving any errors.
Try this:
In the DAC definition, remove the PXSelector attribute (the selector is already being added by LoanAccount.RefNbr())
There is a mismatch between the field's length (30 chars) and the number of characters in the mask (only 15 "C" were added). Change the field's length to 15 (most of Acumatica auto-numbered fields support up to 15 chars)
If these changes still throw the error. To troubleshoot, simplify the code with:
a. Use an Acumatica numbering sequence: i.e. APSetup.batchNumberingID instead of OLSetup.accountNumberingID
b. Simplify the RefNbr() query to use a single table (or change it to a LeftJoin<> rather than an InnerJoin<>)
The issue was resolved by removing ReferentialIntegrity Attributes, refer to link form more information: https://asiablog.acumatica.com/2016/08/using-of-pxrestrictorattribute.html, the same error I was getting for no reason: It gives the uninformative message cannot be found in the system if a record with a given key does not meet the selector condition
I had a similar problem with PXSelectorAttribute, and PXRestrictors doesn't help.
Try to place your DAC's keys field in the same order as at database table constraint.
For example:
CONSTRAINT [SOLine_PK] PRIMARY KEY CLUSTERED
(
[CompanyID] ASC,
[OrderType] ASC,
[OrderNbr] ASC,
[LineNbr] ASC
)
in a DAC:
#region OrderType
...
#endregion
#region OrderNbr
...
#endregion
#region LineNbr
...
#endregion
It helps me in my case
I have been trying to select inventory using 'UsrAlternateIDs' (custom field) value (which are concatenation of cross reference value of stock items). This is where I am trying to implement.
So, if I type in correct InventoryID, it would select me the inventory which exists now. But now, whatever value I type, first it would check if it is the correct inventoryID and select inventory for me. if not it should look for alternateids of inventory item and if I type whichever (separated from ';') it should select inventory item for me.
Here is the code snippet I have written:
protected void FSAppointmentDetPart_InventoryID_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (FSAppointmentDetPart)e.Row;
if(row==null) return;
InventoryItem item = PXSelect<InventoryItem, Where<InventoryItem.inventoryID, Equal<row.InventoryID>>;
if(item!=null)
{
InventoryItem itm = PXSelect<Inventory, Whenre<InventoryItem.alternateIDs, Contains<row.InventoryID>>;
if(itm!=null)
{
}
else
{
throw new PXException("Invalid Inventory Item");
}
}
//sender.SetValue<ContactExt.usrCreditRecordVerified>(e.Row, false);
}
But it is not working. What I am I missing?
Besides, I also looked into the Business logic of the page 'Purchase Orders' which would look for column AlternateIDs and work if is not concatenated and only single value. But the code doesn't make much sense to me. It would be great if you could explain that to me.
Thank you.
If you are trying to make your selector search for both inventory id and the alternate id, consider using the
CrossItemAttribute
Sample usage can be like this, here INPrimaryAlternateType.CPN defines the type of alternate id.
#region InventoryID
public abstract class inventoryID : PX.Data.IBqlField
{
}
protected Int32? _InventoryID;
[CrossItem(INPrimaryAlternateType.CPN, Filterable = true)]
public virtual Int32? InventoryID
{
get
{
return this._InventoryID;
}
set
{
this._InventoryID = value;
}
}
#endregion
EDIT
Tried to use as an unbound field
#region InvID
public abstract class invID : PX.Data.IBqlField { }
[PXInt]
[CrossItem(DisplayName="TEST")]
public virtual int? InvID { get; set; }
#endregion InvID
Item master info
Unbound field, Keys in the barcode
System Finds the correct Item
When I join two DAC in BQL syntax its generates SQL which selects all the columns from both tables. What if I want to select one table's columns in order to reach good execution plan?
You could try to look into PXProjection where the Columns are defined as the fields within the projection class. PXProjection is like a SQL view as a DAC in Acumatica. Just search the Acumatica source for PXProjection and you should find many examples. Note that within the class you need to set BqlField for each "column" so the process knows which table.field your projection field maps to.
Quick join PXProjection below. In this example there will be only 1 column in the DAC and it maps to APRegister.docType
[PXProjection(typeof(Select2<APRegister,
InnerJoin<APInvoice, On<APInvoice.docType, Equal<APRegister.docType>,
And<APInvoice.refNbr, Equal<APRegister.refNbr>>>,
InnerJoin<APPayment, On<APPayment.docType, Equal<APRegister.docType>,
And<APPayment.refNbr, Equal<APRegister.refNbr>>>>>,
Where<APRegister.docType, Equal<APDocType.quickCheck>,
Or<APRegister.docType, Equal<APDocType.voidQuickCheck>>>>), Persistent = true)]
[Serializable]
public partial class APQuickCheck : APRegister
{
#region DocType
public new abstract class docType : PX.Data.IBqlField
{
}
[PXDBString(3, IsKey = true, IsFixed = true, BqlField = typeof(APRegister.docType))]
[PXDefault(APDocType.QuickCheck)]
[APQuickCheckType.List()]
[PXUIField(DisplayName = "Type", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)]
[PXFieldDescription]
public override String DocType
{
get
{
return this._DocType;
}
set
{
this._DocType = value;
}
}
#endregion
}
Here's my field...
#region SessionValidated - unbound
public new abstract class sessionValidated : PX.Data.IBqlField { }
protected bool? _SessionValidated;
[PXBool]
[PXDefault(false)]
[PXUIField(DisplayName = "Validated this Session?")]
public Boolean? SessionValidated
{
get { return this._SessionValidated; }
set { this._SessionValidated = value; }
}
#endregion SessionValidated
So, I'm trying to figure out why, on RowSelected, this field is coming back NULL. Shouldn't it be false, since I specified that in my PXDefault attribute?
Look at PXUnboundDefaultAttribute
[PXUnboundDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
I believe the value (false) will be persisted to the database when the row is persisted.
If you want to see the value upon placement into the cache, you could use the fielddefaulting event to set it.