The client wishes to use the universal search box, to search for values in a custom field. How can this be done?
In this case, I created a simple custom text field, for InventoryItem. Currently, it is not visible in the UI.
Let's refer to the custom UsrAlternateIDs field created in this example and include it into Acumatica's Full-Text Entity Index.
The only modification required to include UsrAlternateIDs field into Full-Text Entity Index is to replace the original declaration of PXSearchableAttribute used on the NoteID field in the InventoryItem DAC. As shown in the code snippet below, UsrAlternateIDs is now included into the fields type array passed as 3rd parameter to the new PXSearchableAttribute constructor:
[PXNonInstantiatedExtension]
public class InventoryItemExt : PXCacheExtension<PX.Objects.IN.InventoryItem>
{
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXRemoveBaseAttribute(typeof(PXSearchableAttribute))]
[PXSearchable(SM.SearchCategory.IN, "{0}: {1}",
new Type[] {
typeof(InventoryItem.itemType),
typeof(InventoryItem.inventoryCD) },
new Type[] {
typeof(InventoryItem.descr),
typeof(InventoryItemExt.usrAlternateIDs) },
NumberFields = new Type[] {
typeof(InventoryItem.inventoryCD),
typeof(InventoryItemExt.usrAlternateIDs) },
Line1Format = "{0}{1}{2}",
Line1Fields = new Type[] {
typeof(INItemClass.itemClassCD),
typeof(INItemClass.descr),
typeof(InventoryItem.baseUnit) },
Line2Format = "{0}",
Line2Fields = new Type[] {
typeof(InventoryItem.descr) },
WhereConstraint = typeof(Where<Current<InventoryItem.itemStatus>,
NotEqual<InventoryItemStatus.unknown>>)
)]
public Guid? NoteID { get; set; }
}
After you implement an InventoryItem extension following the sample above and rebuild Full-Text Entity Index on your Acumatica ERP instance, it should be possible to search for Inventory Items based on their Alternate IDs.
Related
I have a request to add fields to a selector for Location on the Sales Order screen. In standard Acumatica style, this is not a typical selector, but something I've never seen before:
[LocationID(typeof(Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.isActive, Equal<True>,
And<MatchWithBranch<Location.cBranchID>>>>)
,DescriptionField = typeof(Location.descr)
,Visibility = PXUIVisibility.SelectorVisible)]
The fields I need to add are Address1, Address2, City, State, Zip. How would I add these fields to this cryptic selector called 'LocationID'?
I've tried this, but it doesn't work:
[PXRemoveBaseAttribute(typeof(LocationIDAttribute))]
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXSelector(typeof(Search2<Location.locationID,
InnerJoin<Address,
On<Location.defAddressID, Equal<Address.addressID>>>,
Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.isActive, Equal<True>,
And<MatchWithBranch<Location.cBranchID>>>>>)
,typeof(Location.locationCD)
,typeof(Address.addressLine1)
,typeof(Address.addressLine2)
,typeof(Address.city)
,typeof(Address.state)
,typeof(Address.postalCode)
,SubstituteKey = typeof(Location.locationCD)
,DescriptionField = typeof(Location.descr))]
protected virtual void SOOrder_CustomerLocationID_CacheAttached(PXCache sender) { }
This one is a little tricky because the ability to change the column list is protected. We can change the columns by making our own location ID attribute that inherits the one we need to change and then replace the Dimension selector which at that time we can add the columns to be displayed. We also need to join in the address table to display the fields you are looking to add as they are not in the Location DAC.
Here are working examples:
A new attribute which we will use to replace the current attribute on SOOrder CustomerLocaitonID
public class LocationIDExtensionAttribute : LocationIDAttribute
{
public LocationIDExtensionAttribute(params Type[] fieldList)
: this(typeof(Where<boolTrue, Equal<boolTrue>>), fieldList)
{
}
public LocationIDExtensionAttribute(Type WhereType, params Type[] fieldList)
: base(WhereType)
{
AddColumns(WhereType, fieldList);
}
public LocationIDExtensionAttribute(Type WhereType, Type JoinType, params Type[] fieldList)
: base(WhereType, JoinType)
{
AddColumns(WhereType, JoinType, fieldList);
}
protected void AddColumns(Type WhereType, params Type[] fieldList)
{
var dimensionSelector = _Attributes[_SelAttrIndex];
if (dimensionSelector == null)
{
return;
}
_Attributes[_SelAttrIndex] = (PXEventSubscriberAttribute)new PXDimensionSelectorAttribute("LOCATION", BqlCommand.Compose(typeof(Search<,>), typeof(Location.locationID), WhereType), typeof(Location.locationCD), fieldList);
}
protected void AddColumns(Type WhereType, Type JoinType, System.Type[] fieldList)
{
var dimensionSelector = _Attributes[_SelAttrIndex];
if (dimensionSelector == null)
{
return;
}
_Attributes[_SelAttrIndex] = (PXEventSubscriberAttribute)new PXDimensionSelectorAttribute("LOCATION", BqlCommand.Compose(typeof(Search2<,,>), typeof(Location.locationID), JoinType, WhereType), typeof(Location.locationCD), fieldList);
}
}
Then we would use this attribute like this:
[LocationIDExtension(typeof(Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.isActive, Equal<True>,
And<MatchWithBranch<Location.cBranchID>>>>),
typeof(LeftJoin<Address, On<Location.defAddressID, Equal<Address.addressID>>>),
typeof(Location.locationCD),
typeof(Location.descr),
typeof(Address.addressLine1),
typeof(Address.addressLine2),
typeof(Address.city),
typeof(Address.state),
typeof(Address.postalCode),
DescriptionField = typeof(Location.descr),
Visibility = PXUIVisibility.SelectorVisible)]
And we end up with this:
I am trying to add some Qty fields from INSiteStatus to the universal search results for InventoryItem entries. Instead of clicking into the item, we want to save a click and see the info in the search results.
I added the join and the fields to the NoteID (code below) and everything published fine. I tried searching for a stock item and the results for the InventoryItem fields are displayed, but the INSiteStatus fields are skipped.
How do I get the INSiteStatus fields to display?
Code :
[PXSearchable(SM.SearchCategory.IN, "{0}: {1}", new Type[] { typeof(InventoryItem.itemType), typeof(InventoryItem.inventoryCD) },
new Type[] { typeof(InventoryItem.descr) },
NumberFields = new Type[] { typeof(InventoryItem.inventoryCD) },
Line1Format = "{0}{1}", Line1Fields = new Type[] { typeof(InventoryItem.descr),typeof(INSiteStatus.qtyOnHand)},
Line2Format = "{0}{1}{2}", Line2Fields = new Type[] { typeof(InventoryItem.descr),typeof(INSiteStatus.lastModifiedDateTime),typeof(InventoryItem.inventoryCD)},
WhereConstraint = typeof(Where<Current<InventoryItem.itemStatus>, NotEqual<InventoryItemStatus.unknown>>),
MatchWithJoin = typeof(InnerJoin<INSiteStatus, On<INSiteStatus.inventoryID, Equal<InventoryItem.inventoryID>>>),
SelectForFastIndexing = typeof(Select2<InventoryItem, InnerJoin<INSiteStatus, On<InventoryItem.inventoryID, Equal<INSiteStatus.inventoryID>>>>)
)]
[PXNote]
Results from searching...
Finished Good: SLBV4-CO1-DEL
Description: Intel Xeon E5620 2.4/12M/1066 4C 80W
Description: Intel Xeon E5620 2.4/12M/1066 4C 80W - Inventory ID: SLBV4-CO1-DEL
I have a requirement to create a opportunity like screen and I do not know how to implement the auto generating the document number for newly created document
I am looking forward someone to help me on this issue.
The following steps I have used and I have attached the code for review. I am getting error while saving and not generating the number
I have create a numbering sequence for Memo In document
I have created a DAC for Sequence number setup
region MemoInOrderId
public abstract class memoInOrderId : PX.Data.IBqlField
{
}
protected string _MemoInOrderId;
[PXDBString(10, IsUnicode = true)]
[PXDefault("MEMOIN")]
[PXSelector(typeof(Numbering.numberingID),
DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = "Memo In Order Nbr")]
public virtual string MemoInOrderId
{
get
{
return this._MemoInOrderId;
}
set
{
this._MemoInOrderId = value;
}
}
#endregion
I have added Auto Generation Sequence number to MemoIn DAC
`
#region OrderNbr
public abstract class orderNbr : PX.Data.IBqlField
{
}
[PXDBString(10, IsUnicode = true, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "Order Nbr", Visibility = PXUIVisibility.SelectorVisible)]
[AutoNumber(typeof(MemoSetUp.memoInOrderId), typeof(AccessInfo.businessDate))]
[PXSelector(typeof(MemoIN.orderNbr),
new Type[]
{
typeof(MemoIN.orderNbr),
typeof(MemoIN.orderDate),
typeof(MemoIN.vendorId)
})]
public virtual string OrderNbr { get; set; }
#endregion
In the configuration Screen I have selected numbering sequence used for memo in document
While saving the Memo In document I am getting the following error
I have noticed the Order number is not initialized to "NEW" and it is showing "SELECT"
I have gone through CASetup , CMSetup , ARSetup DAC code and not able to figure out the difference.
If we want to use a numbering sequence it is very straight forward in Acumatica. You should have a setup/preferences field somewhere that defines which numbering sequence you will use for your document number field.
Here is an example of a setup field using a selector to pick a numbering sequence:
// Setup field indicating which numbering sequence to use.
public abstract class myNumberingID : PX.Data.IBqlField
{
}
protected String _MyNumberingID;
[PXDBString(10, IsUnicode = true)]
[PXSelector(typeof(Numbering.numberingID), DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = "My Numbering Sequence")]
public virtual String MyNumberingID
{
get
{
return this._MyNumberingID;
}
set
{
this._MyNumberingID = value;
}
}
Next, in your document number field you will use the AutoNumberAttribute to define the field as a consumer of a numbering sequence. Below is an example of a number field using the defined number sequence configured in the setup table above (Assumes "MyNumberingID" exists in DAC/Table "MySetup").
// Field using the numbering sequence...
public abstract class myNumberField : PX.Data.IBqlField
{
}
protected String _MyNumberField;
[PXDBString(15, IsUnicode = true, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "My Number", Visibility = PXUIVisibility.SelectorVisible)]
[AutoNumber(typeof (MySetup.myNumberingID), typeof (AccessInfo.businessDate))]
[PXDefault]
public virtual String MyNumberField
{
get
{
return this._MyNumberField;
}
set
{
this._MyNumberField = value;
}
}
Edit: Make sure in the graph building the documents to include a PXSetup view to the setup table.
Now when you insert and persist a new record on the DAC that contains your number field, the next numbering sequence value will be used (unless the numbering sequence is configured for manual numbering then the user must provide a value).
For a more complex configuration when there are multiple numbering sequences used based on specific conditions/field values, you can look at PX.Objects.IN.INRegister.RefNbr for an example. Look at INDocType.Numbering and how it changes the numbering sequence based on INRegister.docType (shown below). Another example would be sales order order types related to the sales order document.
public class NumberingAttribute : AutoNumberAttribute
{
public NumberingAttribute()
: base(typeof(INRegister.docType), typeof(INRegister.tranDate),
new string[] { Issue, Receipt, Transfer, Adjustment, Production, Change, Disassembly },
new Type[] { typeof(INSetup.issueNumberingID), typeof(INSetup.receiptNumberingID), typeof(INSetup.receiptNumberingID), typeof(INSetup.adjustmentNumberingID), typeof(INSetup.kitAssemblyNumberingID), typeof(INSetup.kitAssemblyNumberingID), typeof(INSetup.kitAssemblyNumberingID) }) { ; }
}
In Cash Sales (AR304000 screen) i want to set it's auto numbering sequence from invoice number sequence to payment number sequence.
i tried the following code but to no avail. saving new sales throws an error. see attached photo for the error.
here is my DAC code:
public class ARCashSaleExtension : PXCacheExtension<ARCashSale>
{
#region RefNumber
[PXDBString(15, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC", IsUnicode = true, BqlField = typeof(**PX.Objects.AR.ARPayment.refNbr**))]
[PXDefault()]
[PXUIField(DisplayName = "Reference Nbr.", Visibility = PXUIVisibility.SelectorVisible)]
[ARPaymentType.RefNbr(typeof(Search2<ARCashSale.refNbr,
InnerJoinSingleTable<Customer, On<ARCashSale.customerID, Equal<Customer.bAccountID>>>,
Where<ARCashSale.docType, Equal<Current<ARCashSale.docType>>,
And2<Where<ARCashSale.origModule, NotEqual<BatchModule.moduleSO>, Or<ARCashSale.released, Equal<boolTrue>>>,
And<Match<Customer, Current<AccessInfo.userName>>>>>, OrderBy<Desc<ARCashSale.refNbr>>>), Filterable = true)]
[**ARPaymentType.Numbering()**]
[PXFieldDescription]
public String RefNbr
{
get;
set;
}
#endregion
}
I think you should use AutoNumberAttribute instead of ARPaymentType.Numbering attribute.
[AutoNumber(typeof(ARCashSale.docType), typeof(ARCashSale.docDate),
new string[] { CashSale, CashReturn },
new Type[] { typeof(ARSetup.paymentNumberingID), typeof(ARSetup.paymentNumberingID) })]
Besides, I can't see any reasons to use ARPaymentType.RefNbr attribute instead of ARCashSaleType.RefNbr attribute.
One more thing: from my point, it's better to use Cache_Attached on graph extension for rewriting attributes on one field instead of creating DAC extension.
Here is an example of Graph extension with CacheAttached:
public partial class ARCashSaleEntryExt : PXGraphExtension<ARCashSaleEntry>
{
[PXMergeAttributes(Method = MergeMethod.Merge)] // that attribute is here to keep all attributes of base field except the one that should be replaced.
[AutoNumber(typeof(ARCashSale.docType), typeof(ARCashSale.docDate),
new string[] { ARDocType.CashSale, ARDocType.CashReturn },
new Type[] { typeof(ARSetup.paymentNumberingID), typeof(ARSetup.paymentNumberingID) })]
public virtual void ARCashSale_RefNbr_CacheAttached(PXCache sender)
{
}
}
To learn more about cache_attached events see T200 training
I am trying to create a Field to store 'VendorID', in my own DAC.
First I tried using Acumatica attributes to show the selector, like the below
[VendorNonEmployeeActive(Visibility = PXUIVisibility.SelectorVisible, DescriptionField = typeof(Vendor.acctName), CacheGlobal = true, Filterable = true)]
AND
[POVendor(Visibility = PXUIVisibility.SelectorVisible, DescriptionField = typeof(Vendor.acctName), CacheGlobal = true, Filterable = true)]
AND other few attributes. but either it shows employee data or nothing. I even tried to write a selector of my own as below where BAccountRef is a class derived from BAccount.
[PXSelector(typeof(Search2<Vendor.bAccountID,
InnerJoin<BAccountRef, On<Vendor.bAccountID, Equal<BAccountRef.bAccountID>>>,
Where<Vendor.status, Equal<BAccountRef.status.active>,
And<Vendor.type, Equal<BAccountType.vendorType>>>>), new Type[] { typeof(BAccountRef.acctCD), typeof(BAccountRef.acctName) },
SubstituteKey = typeof(BAccountRef.acctCD))]
Unfortunately no luck, from the behaviour, it seems like the records are auto filtered to show employee info. I cant figure out how this is happening. How to make the selector show vendor info? How this is auto filtering the employees in this graph?
Most likely your BQL queries towards Vendor DAC are translated into SQL queries to EPEmployee table. This behavior is caused by the EPEmployee cache (and therefore the BAccount cache) initialized prior to Vendor cache.
Try using PX.Objects.AP.VendorAttribute together with the BAccountR DAC - use of BAccountR will break inheritance between the Vendor and BAccount' DACs and should be translated into SQL queries towardsBAccountandVendor` tables:
[Vendor(typeof(Search<BAccountR.bAccountID,
Where<BAccountR.type, Equal<BAccountType.companyType>,
Or<Vendor.type, NotEqual<BAccountType.employeeType>>>>),
Visibility = PXUIVisibility.SelectorVisible, CacheGlobal = true, Filterable = true)]
[PXRestrictor(typeof(Where<Vendor.status, IsNull,
Or<Vendor.status, Equal<BAccount.status.active>,
Or<Vendor.status, Equal<BAccount.status.oneTime>>>>),
AP.Messages.VendorIsInStatus, typeof(Vendor.status))]
Thanks All,
#Ruslan's answer helped to get the correct definition for the selector. When we use BAccountR or VendorR DAC's the SQL is not translating to EPEmployee and hence i am able to get the correct information.
[PXDimensionSelectorAttribute("VENDOR", typeof(Search<VendorR.bAccountID, Where<VendorR.type, Equal<BAccountType.vendorType>,
And<VendorR.status, Equal<BAccount.status.active>>>>), typeof(VendorR.acctCD), new Type[] { typeof(VendorR.acctCD), typeof(VendorR.acctName) })]
In one of my recent projects I've used the following in order to get VendorCD:
#region vendor
public abstract class vendor : PX.Data.IBqlField
{
}
protected string _Vendor;
[VendorRaw(typeof(Where<Vendor.vendorClassID, Equal<Current<VendorFilter.vendorClassID>>>),
DescriptionField = typeof(Vendor.acctName), DisplayName = "Vendor ID")]
[PXDefault("", PersistingCheck = PXPersistingCheck.Nothing)]
public virtual string Vendor
{
get
{
return this._Vendor;
}
set
{
this._Vendor = value;
}
}
#endregion
recently I had to add a Vendor Selector on the ExpenseClaimsDetails DAC, after trying several options, this is the one that worked for me:
[PXDBInt()]
[PXUIField(DisplayName = "Vendor", Enabled = true)]
[PXDimensionSelector("VENDOR", typeof(Search<VendorR.bAccountID, Where<VendorR.vStatus, Equal<VendorStatus.active>>>),
typeof(VendorR.acctCD),
new Type[] { typeof(VendorR.acctCD),
typeof(VendorR.acctName),
typeof(VendorR.vendorClassID),
typeof(VendorR.taxRegistrationID)},
Filterable = true,
SelectorMode = PXSelectorMode.TextModeSearch,
DescriptionField = typeof(VendorR.acctName))]
public int? UsrEVVendorID { get; set; }
public abstract class usrEVVendorID : PX.Data.BQL.BqlInt.Field<usrEVVendorID> { }