Skip to main content
Question

How to Allow Selecting Completed Project Tasks in the Subcontract Screen (POLine.TaskID)?

  • October 26, 2026
  • 2 replies
  • 17 views
  • Translate All

Forum|alt.badge.img

Hi everyone,

I'm customizing the existing TaskID field from the POLine DAC on the Subcontract screen (SC301000) to allow selecting tasks belonging to completed projects.

Currently, when I remove the hold from a subcontract, I receive the following error:

The {0} project is completed.

Customization Code

public class SubcontractEntry_Extension
: PXGraphExtension<SubcontractEntry>
{
[PXDefault(
typeof(Search<PMTask.taskID,
Where<PMTask.projectID,
Equal<Current<POLine.projectID>>,
And<PMTask.isDefault, Equal<True>>>>),
PersistingCheck = PXPersistingCheck.Nothing)]

[PXRemoveBaseAttribute(
typeof(ActiveOrInPlanningProjectTaskAttribute))]

[PXDimensionSelector(
"PROTASK",
typeof(Search<PMTask.taskID,
Where<PMTask.projectID,
Equal<Current<POLine.projectID>>>>),
typeof(PMTask.taskCD),
typeof(PMTask.taskCD),
typeof(PMTask.description),
typeof(PMTask.status),
DescriptionField = typeof(PMTask.description))]

protected virtual void POLine_TaskID_CacheAttached(
PXCache cache)
{
}
}

I tried Merge, Append, and Replace with PXMergeAttributes, but none resolved the issue.

The field now appears as a selector, but the existing value is not displayed, and the selected value disappears after refreshing the screen.

 

Any suggestions or working examples would be greatly appreciated.

Thank you!

2 replies

darylbowman
Captain II
Forum|alt.badge.img+17

I would try creating your own attribute based on BaseProjectTaskAttribute:

[PXRestrictor(typeof(Where<PMTask.isCancelled, Equal<False>>), "Task is Canceled and cannot be used for data entry.", new Type[] { typeof(PMTask.taskCD) })]
public class NotCanceledProjectTaskAttribute : BaseProjectTaskAttribute
{
public NotCanceledProjectTaskAttribute(Type projectID)
: base(projectID)
{
Filterable = true;
}

public NotCanceledProjectTaskAttribute(Type projectID, string Module)
: base(projectID, Module)
{
Filterable = true;
}
}

Then swap it:

public class SubcontractEntry_Extension
: PXGraphExtension<SubcontractEntry>
{
[PXRemoveBaseAttribute(
typeof(ActiveOrInPlanningProjectTaskAttribute))]
[NotCanceledProjectTask]
[PXDefault(
typeof(Search<PMTask.taskID,
Where<PMTask.projectID,
Equal<Current<POLine.projectID>>,
And<PMTask.isDefault, Equal<True>>>>),
PersistingCheck = PXPersistingCheck.Nothing)]
protected virtual void POLine_TaskID_CacheAttached(
PXCache cache) { }
}

 

Translate

Steve Milner
Varsity III
Forum|alt.badge.img+6

@mrthanhkhoi Daryl's attribute swap handles the selector, with two additions. Pass the project field and module when you apply it, and set AllowCompleted: [NotCanceledProjectTask(typeof(POLine.projectID), BatchModule.PO, AllowCompleted = true)]. Without AllowCompleted, BaseProjectTaskAttribute's own FieldVerifying still rejects a completed task unless the user has the Project Accountant role. His attribute also brings back the [PXDBInt]. That isn't on the DAC field itself. It comes in with the task attribute, so your version with a bare PXDimensionSelector had nothing binding the field to the column.

The Remove Hold error is a separate check that no attribute on TaskID can reach. With cost commitment tracking on, Remove Hold builds a PMCommitment record from each project line and copies the line's project and task into it. PMCommitment.ProjectID rejects completed projects and PMCommitment.ProjectTaskID rejects completed tasks. On 26.101, Tools > Trace shows "The HMBAKERY2 project or contract is completed." next to an error on ProjectTaskID, which is the commitment's field name. The line's is TaskID.

This is the version I ran on 26.101. The completed task shows in the lookup and stays on the line after a save, and Remove Hold goes through and creates the commitment on the completed project.

```csharp
using PX.Data;
using PX.Objects.CN.Subcontracts.SC.Graphs;
using PX.Objects.GL;
using PX.Objects.PM;
using PX.Objects.PO;

namespace SubcontractCompletedTasks
{
    public class SubcontractEntry_Extension : PXGraphExtension<SubcontractEntry>
    {
        [PXMergeAttributes(Method = MergeMethod.Merge)]
        [PXRemoveBaseAttribute(typeof(ActiveOrInPlanningProjectTaskAttribute))]
        [BaseProjectTask(typeof(POLine.projectID), BatchModule.PO, AllowCompleted = true, DisplayName = "Project Task")]
        [PXRestrictor(typeof(Where<PMTask.isCancelled, Equal<False>>), PX.Objects.PM.Messages.ProjectTaskIsCanceled, typeof(PMTask.taskCD))]
        protected virtual void _(Events.CacheAttached<POLine.taskID> e) { }

        protected virtual void _(Events.FieldVerifying<PMCommitment, PMCommitment.projectID> e)
        {
            if (PMProject.PK.Find(Base, (int?)e.NewValue)?.IsCompleted == true)
                e.Cancel = true;
        }

        protected virtual void _(Events.FieldVerifying<PMCommitment, PMCommitment.projectTaskID> e)
        {
            if (PMTask.PK.Find(Base, e.Row?.ProjectID, (int?)e.NewValue)?.IsCompleted == true)
                e.Cancel = true;
        }
    }
}
```

The two FieldVerifying handlers only step in when the project or task is completed. They bypass a check Acumatica put there on purpose, so try it in a test tenant first.

Translate