Acumatica Report: How to populate Vendor Location as parameter? - acumatica

I have multiple branches/Locations for Vendors and need it as parameter but when I tried to populate the lookup it returns empty.
Report Parameter
Location View name I used:
=Report.GetFieldSchema('Location.LocationCD')
The result

You can reuse an existing DAC but for more control you may create a Parameter DAC
using PX.Data;
using PX.Objects.CS;
using PX.Objects.GL;
using PX.Objects.CR;
using System;
namespace PX.Objects.AP
{
public class APVendorParameters : IBqlTable
{
#region ActiveVendorID
public abstract class activeVendorID : PX.Data.IBqlField { }
[Vendor]
[PXRestrictor(typeof(Where<Vendor.status, NotEqual<BAccount.status.inactive>>),
Messages.VendorIsInStatus,
typeof(Vendor.status))]
public virtual int? ActiveVendorID { get; set; }
#endregion
#region VendorLocationID
public abstract class vendorLocationID : PX.Data.IBqlField { }
[PXDBInt]
[PXSelector(typeof(Search<Location.locationID, Where<Location.bAccountID, Equal<Optional<activeVendorID>>>>), SubstituteKey = typeof(Location.locationCD), DescriptionField = typeof(Location.locationCD))]
[PXUIField(DisplayName = "Location")]
public virtual Int32? VendorLocationID { get; set; }
#endregion
}
}
In report add 2 parameters:
VendorID (string) ViewName=Report.GetFieldSchema('APVendorParameters.ActiveVendorID')
LocationID (string) ViewName=Report.GetFieldSchema('APVendorParameters.VendorLocationID,VendorID')
The secret stais in
,VendorID')
syntax

Related

how to add a field on the Project Quotes screen PQ000025

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
}

Enabling "AllowAddNew" and/or "AllowEdit" on selector for custom DAC

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

How do I enable custom attributes? (can assign on class, but not displaying for transaction)

I defined several new screens in Acumatica 2018R2 and need to enable attribute support according the class assigned to the transaction. The class screen appears to allow attaching attributes, but the transactional screen does not display any attribute. I found several examples on Stack Overflow, but the only clue I see seems to be that if the class id cannot be determined then no attributes will show. However, upon debug, I see that the class id is found.
This is my test code where I have tried stripping down to a very basic test.
AAClass
using PX.Data;
using System;
namespace Attributes
{
[Serializable]
public class AAClass : IBqlTable
{
#region ClassID
[PXDBIdentity]
[PXUIField(DisplayName = "Class ID")]
public virtual int? ClassID { get; set; }
public abstract class classID : IBqlField { }
#endregion
#region ClassCD
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Class CD")]
public virtual string ClassCD { get; set; }
public abstract class classCD : IBqlField { }
#endregion
#region Descr
[PXDBString(256, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Descr")]
public virtual string Descr { get; set; }
public abstract class descr : IBqlField { }
#endregion
#region CreatedByID
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
public abstract class createdByID : IBqlField { }
#endregion
#region CreatedByScreenID
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
public abstract class createdByScreenID : IBqlField { }
#endregion
#region CreatedDateTime
[PXDBCreatedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldCreatedDateTime)]
public virtual DateTime? CreatedDateTime { get; set; }
public abstract class createdDateTime : IBqlField { }
#endregion
#region LastModifiedByID
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
public abstract class lastModifiedByID : IBqlField { }
#endregion
#region LastModifiedByScreenID
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
public abstract class lastModifiedByScreenID : IBqlField { }
#endregion
#region LastModifiedDateTime
[PXDBLastModifiedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldLastModifiedDateTime)]
public virtual DateTime? LastModifiedDateTime { get; set; }
public abstract class lastModifiedDateTime : IBqlField { }
#endregion
#region Tstamp
[PXDBTimestamp()]
public virtual byte[] Tstamp { get; set; }
public abstract class tstamp : IBqlField { }
#endregion
#region NoteID
[PXNote]
public virtual Guid? NoteID { get; set; }
public abstract class noteID : IBqlField { }
#endregion
}
}
AAClassMaint
using PX.Data;
using PX.Objects.CR;
namespace Attributes
{
public class AAClassMaint : PXGraph<AAClassMaint, AAClass>
{
#region Data Views
[PXViewName("Classes")]
public PXSelect<AAClass> Classes;
[PXViewName("Attributes")]
public CSAttributeGroupList<AAClass, AATag> Mapping;
#endregion
}
}
AATag
using PX.Data;
using PX.Objects.CR;
using PX.Objects.CS;
using System;
namespace Attributes
{
[Serializable]
public class AATag : IBqlTable
{
#region TagID
[PXDBIdentity]
public virtual int? TagID { get; set; }
public abstract class tagID : IBqlField { }
#endregion
#region TagCD
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Tag ID")]
public virtual string TagCD { get; set; }
public abstract class tagCD : IBqlField { }
#endregion
#region MyClassID
[PXDBInt()]
[PXSelector(
typeof(AAClass.classID),
typeof(AAClass.classCD),
typeof(AAClass.descr),
SubstituteKey = typeof(AAClass.classCD)
)]
[PXUIField(DisplayName = "My Class ID")]
public virtual int? MyClassID { get; set; }
public abstract class myClassID : IBqlField { }
#endregion
#region CreatedByID
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
public abstract class createdByID : IBqlField { }
#endregion
#region CreatedByScreenID
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
public abstract class createdByScreenID : IBqlField { }
#endregion
#region CreatedDateTime
[PXDBCreatedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldCreatedDateTime)]
public virtual DateTime? CreatedDateTime { get; set; }
public abstract class createdDateTime : IBqlField { }
#endregion
#region LastModifiedByID
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
public abstract class lastModifiedByID : IBqlField { }
#endregion
#region LastModifiedByScreenID
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
public abstract class lastModifiedByScreenID : IBqlField { }
#endregion
#region LastModifiedDateTime
[PXDBLastModifiedDateTime()]
[PXUIField(DisplayName = SSCS.IN.Messages.FldLastModifiedDateTime)]
public virtual DateTime? LastModifiedDateTime { get; set; }
public abstract class lastModifiedDateTime : IBqlField { }
#endregion
#region Tstamp
[PXDBTimestamp()]
public virtual byte[] Tstamp { get; set; }
public abstract class tstamp : IBqlField { }
#endregion
#region NoteID
[PXNote]
public virtual Guid? NoteID { get; set; }
public abstract class noteID : IBqlField { }
#endregion
#region Attributes
public abstract class attributes : IBqlField { }
[CRAttributesField(typeof(AATag.myClassID))]
public virtual string[] Attributes { get; set; }
public virtual int? ClassID
{
get { return MyClassID; }
}
#endregion
}
}
AATagEntry
using PX.Data;
using PX.Objects.CR;
namespace Attributes
{
public class AATagEntry : PXGraph<AATagEntry, AATag>
{
#region Data Views
[PXViewName("Classes")]
public PXSelect<AATag> Tags;
[PXViewName("Answers")]
public CRAttributeList<AATag> Answers;
#endregion
}
}
As I understand the various posts for this topic, the key requirements are:
Define MAPPING in the class maintenance screen
[PXViewName("Attributes")]
public CSAttributeGroupList<AAClass, AATag> Mapping;
Define ANSWERS in the transactional entry screen
[PXViewName("Answers")]
public CRAttributeList<AATag> Answers;
Include NoteID in the transactional table
Add ATTRIBUTES to the transactional table, including a field for ClassID
public abstract class attributes : IBqlField { }
[CRAttributesField(typeof(AATag.myClassID))]
public virtual string[] Attributes { get; set; }
public virtual int? ClassID
{
get { return MyClassID; }
}
CRAttributesField attribute will build a request with the generic type (classIdField) provided in it's parameter. In your case that would be AATag.myClassID :
protected static Type GetAttributesSearchCommand(Type classIdField)
{
var cmd = BqlCommand.Compose(typeof (Search2<,,>), typeof (CSAttribute.attributeID),
typeof (InnerJoin<,>), typeof (CSAttributeGroup),
typeof (On<,>), typeof (CSAttributeGroup.attributeID), typeof (Equal<>),
typeof (CSAttribute.attributeID),
typeof(Where<,,>), typeof(CSAttributeGroup.entityType), typeof(Equal<>), typeof(Required<>), typeof(CSAttributeGroup.entityType),
typeof (And<,>), typeof (CSAttributeGroup.entityClassID), typeof (Equal<>), typeof (Current<>),
classIdField);
return cmd;
}
So the key part of the request where clause will be:
And<CSAttributeGroup.entityClassID, Equal<Current<AATag.myClassID>>>
This means you must have a current AATag record in memory:
Caches[typeof(AATag)].Current
I suggest you first trace the value (Help->Trace window) to validate it's non null:
public void AATag_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
if (e.Row is AATag)
{
PXTrace.WriteInformation(((AATag)e.Row).myClassID);
}
}
If it is null, you will have to join AATag in the relevant DataView (preferred) or set it explicitely in some events.
Using Acumatica Request Profiler (SM205070
) can also help to determine why the request is not returning any record.
As HB_Acumatica suggested in the comments, the issue appeared to be with the ClassID fields being defined as integer.
I removed the original ClassID (int) fields and renamed the ClassCD (string) fields in the Class DAC's. Next, I changed the ClassID fields in the transactional DAC's to strings. Problem solved. The attribute tab on the transactional entry screens now display the attributes assigned to the class selected.
Lesson learned: A "Class" DAC should not have a ClassID/ClassCD pair, but rather a simple string ClassID field. (Typically named specific to the type of class, i.e. TagClassID) The Class ID used in the transactional tables will then use the string Class ID.

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