Skip to content

Copy Project Contract Term Codes Into Its Budgets ​

This Groovy script links the budget lines of a project to the terms of its contract. When the project contract is saved, every matching line of the contract's estimated budget and executive budget gets the contract term's code in Project Term Code.

Recommended pattern

This script is not tied to any customer's setup. You can paste it as it is; it takes no parameters.

Class nameEAUpdateProjectContractTermCodeInBudgets
ScriptEAUpdateProjectContractTermCodeInBudgets.groovy
Runs onProject Contract, on Post Commit (and optionally Post Delete)
UsesNo parameters. Leave Parameter 1 empty.
Shipped asSource to paste. It is not built into the system.

When to use it ​

A project's estimated and executive budgets list the same work as the project contract, term by term, and each budget line has a Project Term Code that says which contract term it belongs to. When the budget is prepared before the contract is final, or when the contract's terms are renumbered, those codes have to be fixed by hand on every budget line.

With this script the contract keeps its budgets in step: each time the contract is saved, the codes are written again from the contract's own terms.

How it works ​

  1. It opens the contract's budgets. It takes the contract's Contracting Estimated Budget and Contracting Executive Budget. A budget that is not set is skipped.
  2. It matches budget lines to contract terms.
    • An estimated budget line matches a contract term when its own term code is the same as the contract term's code.
    • An executive budget line matches when its Estimated Term Code is the same as the contract term's code. An executive budget line with an empty Estimated Term Code is never matched.
  3. It writes the code. Each matched budget line gets the contract term's code in Project Term Code. Lines that match no term are left as they are.
  4. On delete, it clears the codes. When the line runs on Post Delete, the matched budget lines get an empty Project Term Code instead.

The budgets are changed directly. They are not saved through their own screens, so their own validations and flows do not run.

Setting it up ​

  1. Open Administration → Display Customization → Entity Flow and create a new flow with Target Type set to Project Contract.
  2. Add a line to the Details grid with Target Action set to Post Commit. Paste the whole script from the file above into Groovy Script, and leave Class Name empty: it is filled in when you save.
  3. To clear the codes when a contract is deleted, add a second line with Target Action set to Post Delete and paste the same script.
  4. Save the flow. Class Name shows the script's class name, and the description appears in Description.
ParameterTitle shown after savingWhat to enter
Parameter 1Not used - leave emptyNothing.

Example ​

A contract has eleven terms coded 1 to 11, and its estimated budget has eleven lines with the same term codes. Before the script, the budget's Project Term Code column had been filled in another order: the line for term 2 pointed at contract term 10, the line for term 3 at 11, and so on. After the contract is saved with the script, the budget line for term 2 has Project Term Code 2, the line for term 3 has 3, and every other line likewise points at the contract term with its own code.

The script ​

groovy
package com.namasoft.modules.contracting.domain.utils


import com.namasoft.common.utilities.ObjectChecker
import com.namasoft.infra.domainbase.datafields.LongTextDF
import com.namasoft.infra.domainbase.datafields.TextDF
import com.namasoft.infra.domainbase.entity.base.EntityAction
import com.namasoft.infra.domainbase.util.Result
import com.namasoft.modules.basic.domain.primitives.EntityTargetAction
import com.namasoft.modules.contracting.domain.details.ContrEstimatdBudgetTermLine
import com.namasoft.modules.contracting.domain.details.ContrExecutivBudgetTermLine
import com.namasoft.modules.contracting.domain.details.IBudgetTermLine
import com.namasoft.modules.contracting.domain.details.ProjContractTermLine
import com.namasoft.modules.contracting.domain.entities.IBudgetFile
import com.namasoft.modules.contracting.domain.entities.ProjectContract

import java.util.stream.Collectors

public class EAUpdateProjectContractTermCodeInBudgets implements EntityAction<ProjectContract> {
    @Override
    Result doAction(EntityTargetAction action, ProjectContract object, LongTextDF... parameters) {
        Result result = Result.createAccumulatingResult();
        boolean fromCancel = ObjectChecker.areEqual(action, EntityTargetAction.PostDelete());
        updateProjectTermCodeInBudgets(object.getEstimatedBudget(), object.getTerms(), fromCancel);
        updateProjectTermCodeInBudgets(object.getExecutiveBudget(), object.getTerms(), fromCancel);
        return result;
    }

    private static void updateProjectTermCodeInBudgets(IBudgetFile budget, List<ProjContractTermLine> terms, boolean fromCancel) {
        if (budget == null)
            return;
        for (ProjContractTermLine contractTermLine : terms) {
            List<IBudgetTermLine> budgetLines = budget.fetchTermLines().stream().filter({ l -> termsAreMatched(l, contractTermLine) }).collect(Collectors.toList());
            if (!fromCancel)
                budgetLines.forEach({ l -> l.updateProjectTermCode(contractTermLine.getTermCode()) });
            else
                budgetLines.forEach({ l -> l.updateProjectTermCode(TextDF.EMPTY()) });
        }
    }

    private static boolean termsAreMatched(IBudgetTermLine line, ProjContractTermLine contractLine) {
        if (line instanceof ContrEstimatdBudgetTermLine)
            return ObjectChecker.areEqual(line.getTermCode(), contractLine.getTermCode());
        if (line instanceof ContrExecutivBudgetTermLine)
            return ObjectChecker.areEqual(((ContrExecutivBudgetTermLine) line).getEstimatedTermCode(), contractLine.getTermCode());
        return false;
    }

    @Override
    String describe() {
        return "Project contract: writes each contract term's code into the matching term lines of the contract's estimated budget and executive budget " +
                "(an estimated budget line matches on its term code, an executive budget line on its estimated term code). Run it on Post Commit. " +
                "On Post Delete the same lines are cleared instead. Takes no parameters."
    }

    @Override
    List<String> columnNames() {
        return Arrays.asList("Not used - leave empty")
    }
}