The following is not working:
public class SOLineExt : PXCacheExtension<SOLine>
{
[PXUnboundDefault(typeof(Search<INItemStats.lastCost, Where<INItemStats.inventoryID, Equal<Current<SOLine.inventoryID>>>>))]
[PXDecimal]
[PXUIField(DisplayName = "Last Cost", Enabled = false, Visible = true, IsReadOnly = true)]
public virtual Decimal? UsrLastCost { get; set; }
I have basically the same query running correctly in another customization.
Previously the query was in an event handler and I could see the SQL being executed by running the request profiler. After moving the query to an attributre, the query does not show up in the request profiler.
Reviewing the INItemStatus DAC it contains 2 keys (InventoryID and SiteID). When adding the siteid to the query I was able to return results.
Using this:
[PXUnboundDefault(typeof(Search<INItemStats.lastCost,
Where<INItemStats.inventoryID, Equal<Current<SOLine.inventoryID>>,
And<INItemStats.siteID, Equal<Current<SOLine.siteID>>>>>),
PersistingCheck = PXPersistingCheck.Nothing)]
[PXDecimal]
[PXUIField(DisplayName = "Last Cost", Enabled = false)]
public virtual Decimal? ItemSiteLastCost { get; set; }
Returned the following:
Related
I have customization project in Acumatica 2021R1 (v21.104.0018). I have a parent DAC that has an ID and multiple child DACs that use this ID with a PXParent attribute. Whenever I select the screen in the customization project editor to design it, I get an error message that says, "An item with the same key has already been added." Then, I'm not able to design the screen in the Screen Editor. The weird thing is that I don't get this message when I open the actual screen.
I'm not sure what this is referring to because there are no records in the database in the tables that I'm using for the views of the graph for the screen.
Not sure if anyone else has had this problem and knows what causes it, but Acumatica could really use some more specific error messages.
Here is my parent DAC (note: I left out the system fields here for purposes of space):
public class PSImport : IBqlTable
{
#region Import ID
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXDefault(PersistingCheck = PXPersistingCheck.NullOrBlank)]
[PXUIField(DisplayName = "Import No.", Visibility = PXUIVisibility.SelectorVisible, Enabled = true)]
[AutoNumber(typeof(PSSetup.numberingID), typeof(AccessInfo.businessDate))]
[PXSelector(
typeof(PSImport.importID),
typeof(PSImport.description),
typeof(PSImport.fileFormat),
typeof(PSImport.status),
typeof(PSImport.description)
)]
public virtual string ImportID { get; set; }
public abstract class importID : PX.Data.BQL.BqlString.Field<importID> { }
#endregion
#region Description
[PXDBString(IsUnicode = true, IsFixed = false)]
[PXUIField(DisplayName = "Description")]
public virtual string Description { get; set; }
public abstract class description : PX.Data.BQL.BqlString.Field<description> { }
#endregion
#region File Format
[PXDBString(2, IsFixed = true, IsUnicode = true)]
[PXUIField(DisplayName = "File Format", Enabled = true)]
[PXDefault]
[PXStringList(
new string[]
{
FileFormatTypes.Flats,
FileFormatTypes.IDOA,
FileFormatTypes.MMS,
FileFormatTypes.OCR,
FileFormatTypes.Pressero
},
new string[]
{
FileFormatTypeDisplayNames.Flats,
FileFormatTypeDisplayNames.IDOA,
FileFormatTypeDisplayNames.MMS,
FileFormatTypeDisplayNames.OCR,
FileFormatTypeDisplayNames.Pressero
}
)]
public virtual string FileFormat { get; set; }
public abstract class fileFormat : PX.Data.BQL.BqlString.Field<fileFormat> { }
#endregion
#region Status
[PXDBString(2, IsFixed = true, IsUnicode = true)]
[PXUIField(DisplayName = "Status", Enabled = false)]
[PXDefault(ImportStatusTypes.Unvalidated)]
[PXStringList(
new string[]
{
ImportStatusTypes.Unvalidated,
ImportStatusTypes.Invalid,
ImportStatusTypes.Valid,
ImportStatusTypes.Released
},
new string[]
{
ImportStatusTypeDisplayNames.Unvalidated,
ImportStatusTypeDisplayNames.Invalid,
ImportStatusTypeDisplayNames.Valid,
ImportStatusTypeDisplayNames.Released
}
)]
public virtual string Status { get; set; }
public abstract class status : PX.Data.BQL.BqlString.Field<status> { }
#endregion
#region Date Imported
[PXDBDate]
[PXUIField(DisplayName = "Date Imported", Enabled = false)]
public virtual DateTime? DateImported { get; set; }
public abstract class dateImported : PX.Data.BQL.BqlDateTime.Field<dateImported> { }
#endregion
#region Date of Last Validation
[PXDBDate]
[PXUIField(DisplayName = "Date of Last Validation", Enabled = false)]
public virtual DateTime? DateOfLastValidation { get; set; }
public abstract class dateOfLastValidation : PX.Data.BQL.BqlDateTime.Field<dateOfLastValidation> { }
#endregion
#region Date Released
[PXDBDate]
[PXUIField(DisplayName = "Date Released", Enabled = false)]
public virtual DateTime? DateReleased { get; set; }
public abstract class dateReleased : PX.Data.BQL.BqlDateTime.Field<dateReleased> { }
#endregion
}
Here is one of the child DACs (right now I only have the key because I don't know all of the fields that I need yet, and I'm just trying to start designing the screens):
public class PSTranFlats : IBqlTable
{
#region Import ID
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXDBDefault(typeof(PSImport.importID))]
[PXParent(typeof(SelectFrom<PSImport>.
Where<PSImport.importID.IsEqual<PSTranFlats.importID.FromCurrent>>)
)]
public virtual string ImportID { get; set; }
public abstract class importID : PX.Data.BQL.BqlString.Field<importID> { }
#endregion
}
Here is my setup DAC:
[PXPrimaryGraph(typeof(PSSetupMaint))]
public class PSSetup : IBqlTable
{
#region NumberingID
[PXDBString(10, IsUnicode = true)]
[PXDefault("PSIMPORT")]
[PXUIField(DisplayName = "Import Numbering Sequence")]
[PXSelector(typeof(Numbering.numberingID), DescriptionField = typeof(Numbering.descr))]
public virtual string NumberingID { get; set; }
public abstract class numberingID : PX.Data.BQL.BqlString.Field<numberingID> { }
#endregion
}
Here is my setup graph:
public class PSSetupMaint : PXGraph<PSSetupMaint>
{
#region Selects / Views
public PXSave<PSSetup> Save;
public PXCancel<PSSetup> Cancel;
public SelectFrom<PSSetup>.View Setup;
#endregion
}
And here is my main graph:
public class PSImportEntry : PXGraph<PSImportEntry>
{
#region Selects / Views
public PXCancelClose<PSImport> CancelClose;
public PXSaveClose<PSImport> SaveClose;
public PXSave<PSImport> Save;
public PXCancel<PSImport> Cancel;
public PXInsert<PSImport> Insert;
public PXDelete<PSImport> Delete;
public PXFirst<PSImport> First;
public PXPrevious<PSImport> Previous;
public PXNext<PSImport> Next;
public PXLast<PSImport> Last;
public PXSetup<PSSetup> PSSetup;
public SelectFrom<PSImport>.View Import;
[PXImport(typeof(PSTranFlats))]
public SelectFrom<PSTranFlats>.
Where<PSTranFlats.importID.IsEqual<PSImport.importID.FromCurrent>>.View
FlatsTransactions;
[PXImport(typeof(PSTranIDOA))]
public SelectFrom<PSTranIDOA>.
Where<PSTranIDOA.importID.IsEqual<PSImport.importID.FromCurrent>>.View
IDOATransactions;
[PXImport(typeof(PSTranMMS))]
public SelectFrom<PSTranMMS>.
Where<PSTranMMS.importID.IsEqual<PSImport.importID.FromCurrent>>.View
MMSTransactions;
[PXImport(typeof(PSTranOCR))]
public SelectFrom<PSTranOCR>.
Where<PSTranOCR.importID.IsEqual<PSImport.importID.FromCurrent>>.View
OCRTransactions;
[PXImport(typeof(PSTranPressero))]
public SelectFrom<PSTranPressero>.
Where<PSTranPressero.importID.IsEqual<PSImport.importID.FromCurrent>>.View
PresseroTransactions;
#endregion
}
I am not 100% certain, but I think this is about the ID's in the ASPX rather than the database data. For example:
<px:PXLayoutRule LabelsWidth="S" ControlSize="SM" ID="PXLayoutRule1" runat="server" StartRow="True"></px:PXLayoutRule>
Notice ID="PXLayoutRule1" in that sample. If this "ID" value of any entry in the ASPX is duplicated anywhere in the screen as an ID of another entry, you will get an error.
I had similar issues in an earlier version, especially when I would try to customize a screen and have the customization screen interface crash on me in the middle of it. I'd try deleting the screen, but I'd get orphaned files in the CstDesigner and CstPublished folder, which would really compound my issues.
Hopefully, you know how to look through your ASPX file and the Customization Project XML to check all the ID's. If you do know how to walk through all that, just add something to all of your ID values, like an X at the end. (i.e. PXLayoutRule1X) If not, gaining that familiarity is a worthy side-objective as you continue on.
If your issue is the same as I had in the past and you cannot simply find and edit the duplicate ID in the ASPX file or Project XML, here are some steps to take AFTER you backup your project and the affected folders noted in these steps. And, of course, this also assumes you are working in a development copy of your instance. (I often clone my main DEV instance to my laptop to test things like this if I am unsure so that my DEV instance stays unaffected. It just takes extra time you may or may not have.)
Delete the screen from your customization project.
Locate the folder CstDesigner and CstPublished under your instance's root folder (i.e. AcumticaDEV, Sandbox, etc. where your site exists)
Go into the Pages_XX folder (where XX is the 2 character code for your 1st 2 letters of the screen ID)
Delete the screen file(s) from there, if you find them.
If this is a custom screen, go into the Pages folder which is located in the same root folder of your instance as those folders in step 2 and repeat steps 3 and 4 in that folder.
Check for any reference to your screen in the Project XML from the file menu in the Customization Project screen and remove those sections if they exist. (This tends to relate more for customizing an existing screen.)
Publish your project.
Start over on your page and see if you still get the error.
Again, be sure to get a backup before taking these steps so that you can easily put it back if that does not resolve your problem.
I have a customization to the Bills and Adjustments screen (AP301000), where I'm simply adding 4 user fields to the Document Details tab's grid. I've done this many, many times in the past and I've never seen this error. I have absolutely NO idea what would cause it.
Here's the DAC extension:
[PXCacheName("AP Tran Extension")]
public class APTranExt : PXCacheExtension<APTran>
{
#region UsrACAllocModule
[PXDBString(30, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Allocation Module")]
public virtual string UsrACAllocModule { get; set; }
public abstract class usrACAllocModule : PX.Data.BQL.BqlString.Field<usrACAllocModule> { }
#endregion
#region UsrACAllocBatch
[PXDBString(30, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Allocation Batch")]
public virtual string UsrACAllocBatch { get; set; }
public abstract class usrACAllocBatch : PX.Data.BQL.BqlString.Field<usrACAllocBatch> { }
#endregion
#region UsrACAllocLineNbr
[PXDBInt()]
[PXUIField(DisplayName = "Allocation LineNbr")]
public virtual int? UsrACAllocLineNbr { get; set; }
public abstract class usrACAllocLineNbr : PX.Data.BQL.BqlInt.Field<usrACAllocLineNbr> { }
#endregion
#region UsrACAllocationID
[PXDBString(30, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Allocation ID")]
public virtual string UsrACAllocationID { get; set; }
public abstract class usrACAllocationID : PX.Data.BQL.BqlString.Field<usrACAllocationID> { }
#endregion
}
The database fields exist as follows:
Here is how the fields are added:
And here is the error:
We ran across the same issue. It is a bug in Acumatica. It is resolved in build 20.104.
I have a customization to add user fields to the Employee Time Card screen (EP305000) grid area that's been working through several versions / upgrades - but now in version 20.102.0015 it fails to bring in the data into the user fields.
The user fields are defined as follows:
public class EPTimecardDetailExt : PXCacheExtension<EPTimecardDetail>
{
#region UsrStartDate
public abstract class usrStartDate : IBqlField { }
[PXDBDateAndTime(DisplayNameDate = "Start Date", DisplayNameTime = "Start Time*", UseTimeZone = true)]
//[PXDBTime(DisplayMask = "t", InputMask = "t")]
[PXUIField(DisplayName = "Start Time*")]
public virtual DateTime? UsrStartDate { get; set; }
#endregion
#region UsrEndDate
public abstract class usrEndDate : IBqlField { }
[PXDBDateAndTime(DisplayNameDate = "End Date", DisplayNameTime = "End Time*", UseTimeZone = true)]
//[PXDBTime(DisplayMask = "t", InputMask = "t")]
[PXUIField(DisplayName = "End Time*")]
public virtual DateTime? UsrEndDate { get; set; }
#endregion
#region UsrRelatedCase
public abstract class usrRelatedCase : IBqlField { }
[PXDBString(10)]
[PXUIField(DisplayName = "Related Case*")]
[PXSelector(typeof(Search2<CRCase.caseCD,
InnerJoin<PMProject,
On<CRCase.customerID, Equal<PMProject.customerID>>>,
Where<PMProject.contractID, Equal<Current<EPTimecardDetail.projectID>>>,
OrderBy<Desc<CRCase.caseCD>>>),
typeof(CRCase.caseCD),
typeof(CRCase.subject),
typeof(CRCase.createdDateTime),
typeof(CRCase.caseClassID),
typeof(CRCase.status),
typeof(CRCase.contactID),
typeof(CRCase.ownerID),
DescriptionField = typeof(CRCase.subject))]
//typeof(CRCase.status),
//typeof(CRCase.priority),
//typeof(CRCase.severity),
//typeof(CRCase.caseClassID),
//typeof(BAccount.acctName),
//Filterable = true)]
public virtual string UsrRelatedCase { get; set; }
#endregion
}
The values are in the database - they save correctly - but they won't show up in the grid.
Any idea why this would happen?
The solution to this was provided by Acumatica support.
In my customization, I was creating a Cache Extension for a 'Projection' DAC, namely EPTimeCardDetail. The solution was to create an extension of the DAC which represented the actual table to which the user fields were actually added, which is PMTimeActivity.
Once I created the Cache Extension to PMTimeActivity, the problem was solved and the values were displayed in the grid.
It is unknown why this worked fine in previous versions.
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 am referring to Send Case Reminder project in GitHub where it has LastActivity and LastActivityAge for each case based on which it calculates days and send automatic email notifications.
However, for some reason it is not present in my cases when I implemented the project. So here is what I did.
I created a simple GI from CRCase table and just added three columns to the ResultsGrid, viz. CaseCD, LastActivity & LastActivityAge. What I get is there is no values in LastActivity & LastActivityAge columns for all cases. I am not sure how it works or how should I get the values for these two fields.
I have also checked CRActivityStatistics table for LastIncomingActivityDate and LastOutgoingActivityDate fields. And these two fields has values for all the cases.
Any suggestions would be much appreciated.
PS. I am using 2018 R2 ver 18.201.0050.
Since you do see expected data within the CRActivityStatistics but don’t see the proper values on your GI that would suggest that your join relationship might be incorrect. This could be the issue in your GI and in your code. The proper join is CRCASE.NOTEID = CRACTIVITYSTATISTICS.NOTEID.
I was able to get this through DAC extension
#region LastIncomingActivityDate
public abstract class lastIncomingActivityDate : PX.Data.IBqlField
{
}
[PXDBDate(BqlField = typeof(CRActivityStatistics.lastIncomingActivityDate), PreserveTime = true, UseSmallDateTime = false)]
[PXUIField(DisplayName = "Last Incoming Activity")]
public virtual DateTime? LastIncomingActivityDate { get; set; }
#endregion
#region LastOutgoingActivityDate
public abstract class lastOutgoingActivityDate : PX.Data.IBqlField
{
}
[PXDBDate(BqlField = typeof(CRActivityStatistics.lastOutgoingActivityDate), PreserveTime = true, UseSmallDateTime = false)]
[PXUIField(DisplayName = "Last Outgoing Activity")]
public virtual DateTime? LastOutgoingActivityDate { get; set; }
#endregion
#region LastActivityDate
public abstract class lastActivityDate : IBqlField { }
[PXDBCalced(typeof(Switch<
Case<Where<lastIncomingActivityDate, IsNotNull, And<lastOutgoingActivityDate, IsNull>>, lastIncomingActivityDate,
Case<Where<lastOutgoingActivityDate, IsNotNull, And<lastIncomingActivityDate, IsNull>>, lastOutgoingActivityDate,
Case<Where<lastIncomingActivityDate, Greater<lastOutgoingActivityDate>>, lastIncomingActivityDate>>>,
lastOutgoingActivityDate>),
typeof(DateTime))]
[PXUIField(DisplayName = "Last Activity Date", Enabled = false)]
[PXDate]
public virtual DateTime? LastActivityDate { get; set; }
#endregion
#region UsrLastActivityAge
public abstract class usrLastActivityAge : PX.Data.IBqlField
{
}
[PXTimeSpanLong(InputMask = "#### ds ## hrs ## mins")]
[PXFormula(typeof(Sub<PXDateAndTimeAttribute.now, lastActivityDate>))]
[PXDefault(0)]
[PXUIField(DisplayName = "Last Activity Age")]
public virtual Int32? UsrLastActivityAge { get; set; }
#endregion