Question about three Primary Keys on a DAC - acumatica

In my case I have three Primary Keys,
Primary Key 2 is based on Primary Key 1,
Primary Key 3 is based on Primary Keys 1 and 2
My Question is how do you unset value of a Primary Key DAC Field?
Im trying to work on if I select on the Primary Key 1, Primary Keys 2 and 3 will be unset. I tried cache.SetValueExt<DAC.Field>(data,null); still no luck.
#region FundType
[PXDBString(3, IsKey = true, IsFixed = true, IsUnicode = true, InputMask = "")]
[RMPCFCustodianSetup.FundTypeList]
[PXDefault(RMPCFCustodianSetup.PCFDocType.PCF)]
[PXUIField(DisplayName = "Fund Type", Required =true)]
public virtual string FundType { get; set; }
public abstract class fundType : IBqlField { }
#endregion
#region ReqPayClassID
[PXDBString(10, IsKey = true, IsUnicode = true, InputMask = "")]
[PXSelector(typeof(Search<RMPCFSetup.classID,
Where<RMPCFSetup.fundType, Equal<RMPCFRegister.fundType>>>),
typeof(RMPCFRegister.reqPayClassID),
typeof(RMPCFRegister.descr),
DescriptionField = typeof(RMPCFSetup.descr),
Filterable = true
)]
[PXForeignReference(typeof(Field<reqPayClassID>.IsRelatedTo<RMPCFSetup.classID>))]
[PXUIField(DisplayName = "Request Class", Required =true)]
public virtual string ReqPayClassID { get; set; }
public abstract class reqPayClassID : IBqlField { }
#endregion
#region RefNbr
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = "")]
[PXSelector(typeof(Search<RMPCFRegister.refNbr,
Where<RMPCFRegister.fundType,Equal<Optional2<RMPCFRegister.fundType>>,
And<RMPCFRegister.reqPayClassID,Equal<Optional2<RMPCFRegister.reqPayClassID>>>>>),
typeof(RMPCFRegister.fundType),
typeof(RMPCFRegister.reqPayClassID),
typeof(RMPCFRegister.refNbr),
typeof(RMPCFRegister.extRefNbr),
typeof(RMPCFRegister.descr),
typeof(RMPCFRegister.docAmt),
typeof(RMPCFRegister.dateRequested),
typeof(RMPCFRegister.docStatus)
)]
[PXUIField(DisplayName = "Ref Nbr",Required =true)]
[AutoNumber(typeof(Search<RMPCFSetup.classNumberingID,
Where<RMPCFSetup.fundType, Equal<Optional2<RMPCFRegister.fundType>>,
And<RMPCFSetup.classID,Equal<Optional2<RMPCFRegister.reqPayClassID>>>>>),
typeof(AccessInfo.businessDate))]
public virtual string RefNbr { get; set; }
public abstract class refNbr : IBqlField { }
#endregion`

Related

Adding custom fields to Bills and Adjustment screen causes "nullable object must have a value"

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.

Need help in selector control

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:

InventoryItem BasePrice causing "cast not valid"

I am trying to create a processing page to extract data from several tables which will be used to update the EDI service item list. I keep getting an error that states the specified cast for BasePrice is not valid.
This is simply an internal DAC in the BLC. There is no physical table in the database. If I exclude my BasePrice field everything works fine. If I include it, the insert gets the error. See the code below.
public class EDInventoryProcess : PXGraph<EDInventoryProcess>
{
public PXCancel<EDInventoryFilter> Cancel;
public PXFilter<EDInventoryFilter> Filter;
[PXFilterable]
public PXFilteredProcessingOrderBy<EDInventory, EDInventoryFilter,
OrderBy<Asc<EDInventory.partnerID, Asc<EDInventory.inventoryCD>>>> EDItem;
protected virtual IEnumerable eDItem()
{
EDItem.Cache.Clear();
var cmd = new PXSelectJoin<InventoryItem,
InnerJoin<INItemXRef, On<InventoryItem.inventoryID, Equal<INItemXRef.inventoryID>>,
InnerJoin<EDPartnerInfo, On<INItemXRef.bAccountID, Equal<EDPartnerInfo.customerID>>>>,
Where<INItemXRef.alternateType, Equal<INAlternateType.cPN>,
And<InventoryItem.itemStatus, Equal<InventoryItemStatus.active>>>>(this);
cmd.View.Clear();
var ret = cmd.Select();
if (ret != null)
{
EDInventoryFilter filt = (EDInventoryFilter)Filter.Cache.Current;
EDInventory edInv = new EDInventory();
foreach (PXResult<InventoryItem, INItemXRef, EDPartnerInfo> record in ret)
{
edInv = new EDInventory();
InventoryItem item = (InventoryItem)record;
INItemXRef xref = (INItemXRef)record;
EDPartnerInfo partner = (EDPartnerInfo)record;
edInv.PartnerID = partner.PartnerID;
edInv.InventoryID = item.InventoryID;
edInv.InventoryCD = item.InventoryCD;
edInv.ItemDescr = item.Descr;
edInv.ItemStatus = item.ItemStatus;
edInv.BaseUnit = item.BaseUnit;
edInv.SalesUnit = item.SalesUnit;
edInv.PurchaseUnit = item.PurchaseUnit;
edInv.BasePrice = Convert.ToDecimal(item.BasePrice);
//This is the lint that generates the error.
edInv = EDItem.Insert(edInv);
EDItem.Cache.SetStatus(edInv, PXEntryStatus.Held);
yield return edInv;
}
}
EDItem.Cache.IsDirty = false;
}
Here is the DAC definition:
[Serializable]
public partial class EDInventoryFilter : IBqlTable
{
#region TradingPartner
public abstract class tradingPartner : PX.Data.IBqlField
{
}
protected string _TradingPartner;
[PXString(15)]
[PXUIField(DisplayName = "Trading Partner")]
[PXStringList(new string[] { }, new string[] { })]
public virtual String TradingPartner { get; set; }
#endregion
#region Action
public abstract class action : PX.Data.IBqlField { }
protected string _Action;
[PXString(15)]
[PXUIField(DisplayName = "Action")]
[PXStringList(new string[] { "P" }, new string[] { "Push to EDI" })]
public virtual String Action { get; set; }
#endregion
}
[Serializable]
public partial class EDInventory : IBqlTable
{
#region PartnerID
public abstract class partnerID : IBqlField { }
[PXString(30, IsUnicode = true, IsKey = true)]
[PXDefault("")]
[PXUIField(DisplayName = "Partner")]
public virtual string PartnerID { get; set; }
#endregion
#region InventoryID
public abstract class inventoryID : PX.Data.IBqlField { }
protected Int32? _InventoryID;
[PXInt]
[PXUIField(DisplayName = "Inventory ID", Visibility = PXUIVisibility.Visible, Visible = false)]
public virtual Int32? InventoryID { get; set; }
#endregion
#region InventoryCD
public abstract class inventoryCD : PX.Data.IBqlField { }
protected String _InventoryCD;
[PXDefault()]
[InventoryRaw(IsKey = true, DisplayName = "Inventory ID")]
public virtual String InventoryCD { get; set; }
#endregion
#region ItemDescr
public abstract class itemDescr : PX.Data.IBqlField { }
protected String _ItemDescr;
[PXString(255, IsUnicode = true)]
[PXUIField(DisplayName = "Item Description")]
public virtual String ItemDescr { get; set; }
#endregion
#region ItemStatus
public abstract class itemStatus : PX.Data.IBqlField { }
protected String _ItemStatus;
[PXString(2, IsFixed = true)]
[PXDefault("AC")]
[PXUIField(DisplayName = "Item Status", Visibility = PXUIVisibility.SelectorVisible)]
public virtual String ItemStatus { get; set; }
#endregion
#region BaseUnit
public abstract class baseUnit : PX.Data.IBqlField { }
protected String _BaseUnit;
[PXString]
[PXDefault("")]
[PXUIField(DisplayName = "Base Unit", Visibility = PXUIVisibility.SelectorVisible)]
public virtual String BaseUnit { get; set; }
#endregion
#region SalesUnit
public abstract class salesUnit : PX.Data.IBqlField { }
protected String _SalesUnit;
[PXString]
[PXDefault("")]
[PXUIField(DisplayName = "Sales Unit", Visibility = PXUIVisibility.SelectorVisible)]
public virtual String SalesUnit { get; set; }
#endregion
#region PurchaseUnit
public abstract class purchaseUnit : PX.Data.IBqlField { }
protected String _PurchaseUnit;
[PXString]
[PXDefault("")]
[PXUIField(DisplayName = "Purchase Unit", Visibility = PXUIVisibility.SelectorVisible)]
public virtual String PurchaseUnit { get; set; }
#endregion
#region BasePrice
public abstract class basePrice : PX.Data.IBqlField { }
protected Decimal? _BasePrice;
[PXPriceCost()]
[PXDefault(0.0)]
[PXUIField(DisplayName = "Default Price", Visibility = PXUIVisibility.SelectorVisible)]
public virtual Decimal? BasePrice { get; set; }
#endregion
}
I just discovered what might be the answer. I was listing the default value as
[PXDefault(0.0)]
but I found another reference for decimal default as
[PXDefault(TypeCode.Decimal, "0.0")]
which seems to work. I no longer get the error and my processing screen displays as expected. I had assumed the default value drew its type from the object.
Yes for Decimal fields set [PXDefault(TypeCode.Decimal, "0.0")] attribute to avoid casting issues.

Acumatica - Possible to create several numberingId with existing numberingId

i have some problems with AutoNumberAttribute in Acumatica. In my Project Issue screen i can create new entity with existing numberingId (see screenshot below)
Field selector with AutoNumberAttribute
But other entities like POOrder, Case haven't this promlems. Code for this shown below:
[Serializable]
[PXEMailSource]
[PXPrimaryGraph(typeof(ProjectIssueMaint))]
[PXCacheName(Messages.ProjectIssue.CacheName)]
public class ProjectIssue : BaseCache, IBqlTable, IAssign, IPXSelectable
{
[PXDBIdentity]
[PXUIField(Visible = false, Visibility = PXUIVisibility.Invisible, DisplayName = Messages.ProjectIssue.NumberId)]
public virtual int? ProjectIssueId
{
get;
set;
}
[PXDefault]
[PXFieldDescription]
[PXDBString(10, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = Messages.ProjectIssue.NumberId, Required = true)]
[PXSelector(typeof(Search<projectIssueCd>),
typeof(projectIssueCd),
typeof(projectId),
typeof(projectTaskId),
typeof(classId),
typeof(summary),
typeof(status),
typeof(ownerID),
Filterable = true)]
[AutoNumber(typeof(ProjectManagementSetup.projectIssueNumberingId), typeof(createdDateTime))]
public virtual string ProjectIssueCd
{
get;
set;
}
public abstract class projectIssueCd : IBqlField
{
}
public abstract class projectIssueId : IBqlField
{
}
}
[Serializable]
[PXCacheName(Messages.ProjectManagementSetup.CacheName)]
public class ProjectManagementSetup : BaseCache, IBqlTable
{
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(Constants.ProjectIssue.NumberingId)]
[PXSelector(typeof(Numbering.numberingID), DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = Messages.ProjectManagementSetup.ProjectIssueNumberingSequence)]
public virtual string ProjectIssueNumberingId
{
get;
set;
}
public abstract class projectIssueNumberingId : IBqlField
{
}
}
public class ProjectIssueMaint : PXGraph<ProjectIssueMaint, ProjectIssue>
{
[PXViewName(Messages.ProjectIssue.CacheName)]
[PXCopyPasteHiddenFields(typeof(ProjectIssue.status))]
public PXSelect<ProjectIssue> ProjectIssue;
[PXHidden]
[PXCheckCurrent]
public PXSetup<ProjectManagementSetup> ProjectManagementSetup;}
public class ProjectManagementSetupMaint : PXGraph<ProjectManagementSetupMaint>
{
public PXSave<ProjectManagementSetup> Save;
public PXCancel<ProjectManagementSetup> Cancel;
public PXSelect<ProjectManagementSetup> ProjectManagementSetup;
}
I reproproduce this issue by change the last number field in the numbering sequence screen (see screenshot https://snag.gy/UpIe8a.jpg).
So somebody know why this maybe happend? Any information will help me)
The AutoNumberAttribute completely relies on the configuration of the associated Numbering Sequence and does not have built-in validation to prevent insertion of the record with the duplicated number, which was generated by the AutoNumberAttribute. Since your table is built with A Pair of Columns with Key Substitution in the UI, you must add a unique index consisting of the CompanyID and ProjectIssueCd columns to prevent the insertion of multiple ProjectIssue records with the same ProjectIssueCd on the database level.
CREATE UNIQUE NONCLUSTERED INDEX [ProjectIssue_ProjectIssueCd_Uindex] ON [dbo].[ProjectIssue]
(
[CompanyID] ASC,
[ProjectIssueCd] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

Customizing Selector when another another Selector value changes

I need to Customize CaseClassID Selector on Cases Screen. It should refresh with different values when Contract field is selected on the CaseScreen under the Additional Info tab. Right now the CaseClass is displaying values from CRCase table.But, now if the contract changes the fieldupdatedEvent should be triggered and CaseClassID selector should have values accordingly. Please suggest me how to customize the CaseClassID selector inside FieldUpdated Event Handler
protected virtual void CRCase_ContractID_FieldUpdated(PXCache sender,
PXFieldUpdatedEventArgs e)
{
CRCase cc = (CRCase)e.Row;
if (cc == null) return;
CRCase_CaseClassID_CacheAttached(sender);
}
[PXMergeAttributes(Method = MergeMethod.Replace)]
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(typeof(Search<CRSetup.defaultCaseClassID>))]
[PXUIField(DisplayName = "Class ID")]
[PXSelector(typeof(Search2<CRCaseClass.caseClassID,
InnerJoin<CaseContract, On<CaseContract.caseClassID,
Equal<CRCaseClass.caseClassID>>,
InnerJoin<Contract, On<CaseContract.contractID,
Equal<Contract.templateID>>,
InnerJoin<CRCase, On<Contract.contractID,
Equal<Current<CRCase.contractID>>>>>>,
Where<CaseContract.active, Equal<True>>>),
DescriptionField = typeof(CRCaseClass.description),
CacheGlobal = true)]
[PXMassUpdatableField]
public virtual String CaseClassID { get; set; }
public virtual void CRCase_CaseClassID_CacheAttached(PXCache sender){
}
Override CaseClassID selector and add your custom logic in its type parameter.
You can create a custom unbound field to filter the selector according to your business logic. When you want to change selector filter, just change the custom field.
#region CaseClassID
public abstract class caseClassID : IBqlField { }
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(typeof(Search<CRSetup.defaultCaseClassID>))]
[PXUIField(DisplayName = "Class ID")]
// Use your custom field (filterCaseClassID) in the selector type parameter
[PXSelector(typeof(Search<CRCaseClass.caseClassID,
Where<CRCaseClass.caseClassID, Equal<filterCaseClassID>>>),
DescriptionField = typeof(CRCaseClass.description),
CacheGlobal = true)]
[PXMassUpdatableField]
public virtual String CaseClassID { get; set; }
#endregion
#region FilterCaseClassID
public abstract class filterCaseClassID : IBqlField { }
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
// Change the value of your custom field to set the selector filter
public virtual String FilterCaseClassID { get; set; }
#endregion
EDIT overriding DAC field in graph extension and filtering Selector by using a field from another DAC:
using PX.Data;
using PX.Objects.CR.MassProcess;
using System;
namespace PX.Objects.CR
{
[Serializable]
public class CaseContract : IBqlTable
{
public abstract class caseClassID : IBqlField { }
[PXString(10, IsUnicode = true)]
[PXUIField(DisplayName = "Case Class ID")]
[PXSelector(typeof(CRCaseClass.caseClassID),
DescriptionField = typeof(CRCaseClass.description))]
public virtual String CaseClassID
{
get; set;
}
}
public class CRCaseMaint_Extension : PXGraphExtension<CRCaseMaint>
{
[PXMergeAttributes(Method = MergeMethod.Replace)]
[PXDBString(10, IsUnicode = true, InputMask = ">aaaaaaaaaa")]
[PXDefault(typeof(Search<CRSetup.defaultCaseClassID>))]
[PXUIField(DisplayName = "Class ID")]
[PXSelector(typeof(Search<CRCaseClass.caseClassID,
Where<Current<CaseContract.caseClassID>, IsNull,
Or<CRCaseClass.caseClassID, Equal<Current<CaseContract.caseClassID>>>>>),
DescriptionField = typeof(CRCaseClass.description),
CacheGlobal = true)]
[PXMassUpdatableField]
public virtual void CRCase_CaseClassID_CacheAttached(PXCache sender)
{
}
}
}

Resources