Reputation: 155
How do I reference the project ID in an Expense Receipt, to validate the value before it is saved? I would like to block use of the non-project code.
When I attempt to publish the code below, I receive the error:
\App_RuntimeCode\ExpenseClaimDetailEntry.cs(31): error CS0426: The type name 'ContractID' does not exist in the type 'ExpenseClaimDetailEntry'
The code that produces the error:
protected virtual void _(Events.FieldVerifying<ExpenseClaimDetailEntry.ContractID> e) //<-- Line 31
{
if (e != null)
{
if ((string?)e.NewValue == "XXXXXXXX");
{
throw new PXSetPropertyException("Non-Project Code XXXXXXXX cannot be used in expense reciepts.");
}
}
}
Thank you for your help!
Edit: This is my solution. Remove the default value using e.NewValue = null
and e.Cancel = true
, then block selection of the non-project code using PXSetPropertyException
. YMMV.
protected void EPExpenseClaimDetails_contractID_FieldDefaulting(
PXCache sender, PXFieldDefaultingEventArgs e)
{
e.NewValue = null;
e.Cancel = true; //Skip the standard FieldDefaulting code - It will revert ContractId to zero again!
}
protected void EPExpenseClaimDetails_contractID_FieldVerifying(Events.FieldVerifying<EPExpenseClaimDetails.contractID> e)
{
if ((int?)e.NewValue == 0)
{
throw new PXSetPropertyException("Error: Project 'X' not allowed in expense reciepts.", PXErrorLevel.Error);
}
}
Upvotes: 0
Views: 282
Reputation: 8278
For each DAC field, there are two variables declared.
1 There is a property (ContractID). By convention the property starts with a upper-case letter:
[ProjectDefault("EA", AccountType = typeof(expenseAccountID))]
[PXDBInt]
[PXDimensionSelector("CONTRACT", typeof(Search2<Contract.contractID, LeftJoin<EPEmployeeContract, On<EPEmployeeContract.contractID, Equal<Contract.contractID>, And<EPEmployeeContract.employeeID, Equal<Current2<employeeID>>>>>, Where<Contract.isActive, Equal<True>, And<Contract.isCompleted, Equal<False>, And<Where<Contract.nonProject, Equal<True>, Or2<Where<Contract.baseType, Equal<CTPRType.contract>, And<FeatureInstalled<FeaturesSet.contractManagement>>>, Or<Contract.baseType, Equal<CTPRType.project>, And2<Where<Contract.visibleInEA, Equal<True>>, And2<FeatureInstalled<FeaturesSet.projectModule>, And2<Match<Current<AccessInfo.userName>>, And<Where<Contract.restrictToEmployeeList, Equal<False>, Or<EPEmployeeContract.employeeID, IsNotNull>>>>>>>>>>>>, OrderBy<Desc<Contract.contractCD>>>), typeof(Contract.contractCD), new[] { typeof(Contract.contractCD), typeof(Contract.description), typeof(Contract.customerID), typeof(Contract.status) }, Filterable = true, ValidComboRequired = true, CacheGlobal = true, DescriptionField = typeof(Contract.description))]
[PXUIField(DisplayName = "Project/Contract")]
public virtual int? ContractID { get; set; }
The property is used when you want to get or set the value of the field.
2 The other variable is an abstract class (contractID). By convention it starts with lower-case letter:
public abstract class contractID : BqlType<IBqlInt, int>.Field<contractID>
The abstract class is used when you refer to a field as a pointer. It identifies a field but doesn't hold a value.
In your example you are declaring an event handler. For this you need to use the abstract class because the event points to the field instead of getting/setting the field value. Change 'ContractID' to 'contractID':
void _(Events.FieldVerifying<ExpenseClaimDetail.contractID> e)
There's a second error, the class EPExpenseClaimDetailsEntry
is a graph, not a DAC. Fields are in DAC (data access class) not in graph. So you have to use the DAC EPExpenseClaimDetails
instead of the graph EPExpenseClaimDetailsEntry
for the event handler generic type.
Upvotes: 2