C02
C02

Reputation: 155

Acumatica - Field Verifying on ContractID

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

Answers (1)

Hugues Beaus&#233;jour
Hugues Beaus&#233;jour

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

Related Questions