Skip to content

Set a Default Locator on Lines Without One ​

These two Groovy scripts fill an empty locator on document lines with a default locator that you name. The first one does it for every item. The second one does it only for items of the item sections you list, and lets you exclude single items.

Recommended pattern

These scripts are not tied to any customer's setup. You control them entirely through their parameters.

Class namesEASetDefaultLocatorIfEmpty and EASetDefaultLocatorForItemSections
ScriptsEASetDefaultLocatorIfEmpty.groovy, EASetDefaultLocatorForItemSections.groovy
Runs onAny supply chain document with lines. Target action Pre Update Calculated Fields.
UsesParameter 2 (first script), or Parameters 2 to 4 (second script). Leave Parameter 1 empty.
Shipped asSource to paste. It is not built into the system.

When to use them ​

In a warehouse whose Locator Usage is Required, every line must name a locator, or the save is refused with the message The field {0} can not be empty, at line {1} , item is {2}, where {0} is Locator. That is right for shelved stock, but some goods always land in the same place: a receiving bay, a bulk area, a "service parts" shelf. Asking the user to pick that locator on every line is busywork.

  • Use EASetDefaultLocatorIfEmpty when every line without a locator should go to one default locator, for example the receiving bay RCV-01.
  • Use EASetDefaultLocatorForItemSections when only some kinds of items have a fixed place, for example all items of the sections SERV and CONS go to locator SVC-SHELF, except two items that are stored elsewhere.

A line that already has a locator is never changed, so users can still choose a different locator when they need to.

How they work ​

Both scripts look up the locator first. If the code or id in the locator parameter does not match any locator, the script refuses the save with the message below, for every document it runs on. Then, for each line that has an item and no locator:

  1. It finds the warehouse. A line with no warehouse first takes the document's warehouse. If the document has no warehouse either, the line is skipped.
  2. It checks the warehouse. The line is skipped when its warehouse prevents locators, or when it is not the warehouse that the default locator belongs to. A default locator therefore only ever lands in its own warehouse; lines in other warehouses are left alone.
  3. It sets the locator. The first script sets it on every remaining line. The second one sets it only when the item's Item Section code is in the list in Parameter 2 and the item code is not in the list in Parameter 3.

One element per warehouse

Each element covers one locator, and so one warehouse. To give several warehouses their own default locator, add one element per warehouse to the same flow, each with its own locator in the parameter.

The analysis set in the section version

EASetDefaultLocatorForItemSections also copies the warehouse's analysis set onto each line it looks at. When tested on a stock issue, the saved lines still carried the document's analysis set, so do not rely on this step to change a line's analysis set.

Setting them up ​

  1. Open Administration → Display Customization → Entity Flow and create a flow whose target type is the document to cover (for example Stock Issue).
  2. In the Details grid, add a line with Target Action set to Pre Update Calculated Fields, and paste the whole script you chose into its Groovy Script column. Leave Class Name empty: it is filled in when you save.
  3. Fill in the parameters and save the flow.

EASetDefaultLocatorIfEmpty

ParameterTitle shown after savingWhat to enter
Parameter 1Not used - leave emptyNothing.
Parameter 2Default Locator Code Or IdThe code of the default locator, for example RCV-01.

EASetDefaultLocatorForItemSections

ParameterTitle shown after savingWhat to enter
Parameter 1Not used - leave emptyNothing.
Parameter 2Apply On Section Codes (CSV)The item section codes, separated by commas with no spaces, for example SERV,CONS.
Parameter 3Excluded Item Codes(CSV)Item codes that never get the default locator, separated by commas with no spaces. Leave it empty to exclude none.
Parameter 4Default Locator Code Or IdThe code of the default locator, for example SVC-SHELF.

Example ​

Warehouse MAIN requires locators, and locator SVC-SHELF belongs to it. The section version is set up with Parameter 2 SERV, Parameter 3 SRV-099 and Parameter 4 SVC-SHELF. A stock issue from MAIN has three lines with no locator:

LineItemItem sectionAfter saving
1SRV-001SERVLocator SVC-SHELF.
2SRV-099SERVNo locator: the item is excluded.
3RAW-010RAWNo locator: the section is not listed.

Lines 2 and 3 still need a locator from the user before the warehouse accepts the issue.

Messages you may see ​

This message has no Arabic translation, so it appears in English on Arabic screens as well. The product text ends with a space after {0}.

MessageWhyWhat to do
Could not find a locator with the code {0} The locator parameter (Parameter 2 or Parameter 4) does not match any locator. {0} is the value you entered. Every save of the target document is refused until this is fixed.Correct the locator code in the flow, or deactivate the element.

The scripts ​

EASetDefaultLocatorIfEmpty

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

import com.namasoft.common.utilities.ObjectChecker
import com.namasoft.infra.domainbase.datafields.LongTextDF
import com.namasoft.infra.domainbase.entity.base.EntityAction
import com.namasoft.infra.domainbase.persistence.repos.Persister
import com.namasoft.infra.domainbase.util.Result
import com.namasoft.modules.supplychain.domain.details.BasicSCDocumentLine
import com.namasoft.modules.supplychain.domain.entities.BasicSCDocument
import com.namasoft.modules.supplychain.domain.entities.Locator
import com.namasoft.modules.supplychain.domain.valueobjects.ItemSpecificDimensions

public class EASetDefaultLocatorIfEmpty implements EntityAction<BasicSCDocument> {
    @Override
    public Result doAction(BasicSCDocument src, LongTextDF... parameters) {
        Result result = Result.createAccumulatingResult();
        Locator defaultLocator = Persister.findByIdOrCode(Locator.class, parameters[1].getPrimitiveValue());
        if (defaultLocator == null) {
            Result.createFailureResult("Could not find a locator with the code {0} ", parameters[1]).addToAccumulatingResult(result);
            return result;
        }
        for (final BasicSCDocumentLine l in src.getDetails()) {
            if (l.fetchItem() == null)
                continue;
            if (l.fetchLocator() != null)
                continue;
            if (l.getSpecificDimensions() == null)
                l.setSpecificDimensions(new ItemSpecificDimensions());
            if (l.fetchWarehouse() == null) {
                if (src.getWarehouse() == null)
                    continue;
                l.getSpecificDimensions().setWarehouse(src.getWarehouse());
            }
            if (l.fetchWarehouse().calcLocatorPolicy().isPrevented())
                continue;
            if (ObjectChecker.areNotEqual(l.fetchWarehouse(), defaultLocator.getWarehouse()))
                continue;
            l.getSpecificDimensions().setLocator(defaultLocator);
        }
        return result;
    }


    @Override
    public String describe() {
        return "Puts the locator given in parameter 2 (code or id) on every document line that has an item and no locator, when the " +
                "line's warehouse is the locator's warehouse and that warehouse does not prevent locators. A line with no warehouse " +
                "first takes the document's warehouse. The save is refused when the locator is not found. Parameter 1 is not used.";
    }

    @Override
    public List<String> columnNames() {
        return Arrays.asList("Not used - leave empty", "Default Locator Code Or Id");
    }
}

EASetDefaultLocatorForItemSections

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

import com.namasoft.common.utilities.ObjectChecker
import com.namasoft.infra.domainbase.datafields.EntityCodeDF
import com.namasoft.infra.domainbase.datafields.LongTextDF
import com.namasoft.infra.domainbase.entity.base.EntityAction
import com.namasoft.infra.domainbase.persistence.repos.Persister
import com.namasoft.infra.domainbase.util.Result
import com.namasoft.modules.supplychain.domain.details.BasicSCDocumentLine
import com.namasoft.modules.supplychain.domain.entities.BasicSCDocument
import com.namasoft.modules.supplychain.domain.entities.InvItem
import com.namasoft.modules.supplychain.domain.entities.Locator
import com.namasoft.modules.supplychain.domain.valueobjects.ItemSpecificDimensions

import java.util.stream.Collectors
import java.util.stream.Stream

public class EASetDefaultLocatorForItemSections implements EntityAction<BasicSCDocument> {
    @Override
    public Result doAction(BasicSCDocument src, LongTextDF... parameters) {
        Result result = Result.createAccumulatingResult();
        List<EntityCodeDF> sections = Stream.of(parameters[1].getPrimitiveValue().split(",")).map { EntityCodeDF.fromString(it) }.distinct().collect(Collectors.toList());
        List<EntityCodeDF> excludedItems = Stream.of(parameters[2].getPrimitiveValue().split(",")).map { EntityCodeDF.fromString(it) }.distinct().collect(Collectors.toList());
        Locator defaultLocator = Persister.findByIdOrCode(Locator.class, parameters[3].getPrimitiveValue());
        if (defaultLocator == null) {
            Result.createFailureResult("Could not find a locator with the code {0} ", parameters[3]).addToAccumulatingResult(result);
            return result;
        }
        for (final BasicSCDocumentLine l in src.getDetails()) {
            if (l.fetchItem() == null)
                continue;
            if (l.fetchLocator() != null)
                continue;
            if (l.getSpecificDimensions() == null)
                l.setSpecificDimensions(new ItemSpecificDimensions());
            if (l.fetchWarehouse() == null) {
                if (src.getWarehouse() == null)
                    continue;
                l.getSpecificDimensions().setWarehouse(src.getWarehouse());
            }
            l.getGenericDimensions().setAnalysisSet(l.fetchWarehouse().getAnalysisSet());
            if (l.fetchWarehouse().calcLocatorPolicy().isPrevented())
                continue;
            if (ObjectChecker.areNotEqual(l.fetchWarehouse(), defaultLocator.getWarehouse()))
                continue;
            if (shouldSetLocator(l.fetchItem(), sections, excludedItems))
                l.getSpecificDimensions().setLocator(defaultLocator);
        }
        return result;
    }

    private boolean shouldSetLocator(InvItem item, List<EntityCodeDF> sections, List<EntityCodeDF> excludedItems) {
        if (excludedItems.contains(item.getCode()))
            return false;
        if (item.getSection() == null)
            return false;
        if (!sections.contains(item.getSection().getCode()))
            return false;
        return true;
    }

    @Override
    public String describe() {
        return "Puts the locator given in parameter 4 (code or id) on every document line that has no locator, when the item's section " +
                "code is listed in parameter 2 (comma separated), the item code is not listed in parameter 3 (comma separated), the " +
                "line's warehouse is the locator's warehouse and that warehouse does not prevent locators. A line with no warehouse first " +
                "takes the document's warehouse. " +
                "The save is refused when the locator is not found. Parameter 1 is not used.";
    }

    @Override
    public List<String> columnNames() {
        return Arrays.asList("Not used - leave empty",
                "Apply On Section Codes (CSV)", "Excluded Item Codes(CSV)", "Default Locator Code Or Id");
    }
}