Skip to content

Learn an Item's Default Locator From Stock Movements ​

These two Groovy scripts teach each Item where it lives. When a Stock Transfer or an Opening Stock Document is saved, the locator it put the item in becomes the item's default locator in that warehouse.

Recommended pattern

These scripts are not tied to any customer's setup. You can paste them as they are; they take no parameters.

Class namesEALearnDefaultLocatorFromStockTransfer (stock transfer) and EALearnDefaultLocatorFromOpeningStock (opening stock)
ScriptsEALearnDefaultLocatorFromStockTransfer.groovy, EALearnDefaultLocatorFromOpeningStock.groovy
Runs onStock Transfer or Opening Stock Document, on the Post Commit event
UsesNo parameters. Leave Parameter 1 empty.
Shipped asSource to paste. It is not built into the system.

When to use it ​

In a warehouse whose Locator Usage is Required, every document line needs a locator. When a line leaves it empty and the warehouse has no default locator of its own, the system looks at the item: the line of the item's Details grid for that warehouse that is ticked as the default locator supplies it. Keeping those lines up to date by hand, for thousands of items, is not realistic.

These scripts keep them up to date from the stock movements themselves. Load the opening stock into its shelves, or move an item to a new shelf with a stock transfer, and from then on documents in that warehouse fill that shelf for the item by themselves.

How it works ​

For every line of the saved document:

  1. It finds the warehouse and locator the line put the item in. On a stock transfer that is the line's to warehouse and to locator. On an opening stock document it is the line's warehouse and locator.
  2. It finds the item's line for that warehouse in the item's Details grid.
    • If that line already has the same locator, nothing is done for this document line.
    • If it has another locator, the line is updated.
    • If the item has no line for that warehouse, one is added.
  3. It sets the line to the warehouse and the locator, and ticks it as the default locator. The stock transfer script also ticks Desirable.
  4. It saves the item. The item goes through its normal save, so its own validations apply.

The scripts run on Post Commit, after the document itself is saved.

Use it where every line has a locator

The scripts copy the line's locator as it is. A line without a locator would leave the item's line for that warehouse with an empty locator. In a warehouse whose Locator Usage is Required, every line has one, so attach the flow to documents in such warehouses.

Setting it up ​

  1. Open Administration → Display Customization → Entity Flow and create a new flow.
  2. Set Target Type to Stock Transfer (or Opening Stock Document) and Target Action to Post Commit.
  3. In the Details grid, paste the matching script into Groovy Script. Leave Class Name empty: it is filled in when you save.
  4. Save the flow. For both document types, create one flow for each, each with its own script.
ParameterTitle shown after savingWhat to enter
Parameter 1Not used - leave emptyNothing.

Example ​

A new item is loaded with an opening stock document into warehouse WH1, locator L1. After the document is saved, the item's Details grid has a new line:

WarehouseLocatorDefault locatorDesirable
WH1L1✓

Later, a stock transfer moves part of the stock within WH1 from L1 to L2. After it is saved, the same line reads:

WarehouseLocatorDefault locatorDesirable
WH1L2✓✓

Messages you may see ​

The scripts raise no messages of their own. If the item cannot be saved, the item's own validation messages are shown.

The script ​

The stock transfer script:

groovy
package com.namasoft.modules.supplychain.domain.utils.plugnplay.groovy

import com.namasoft.common.utilities.ObjectChecker
import com.namasoft.infra.domainbase.common.detail.EntityDetailLine
import com.namasoft.infra.domainbase.datafields.BooleanDF
import com.namasoft.infra.domainbase.datafields.LongTextDF
import com.namasoft.infra.domainbase.entity.base.EntityAction
import com.namasoft.infra.domainbase.entity.base.EntityMediator
import com.namasoft.infra.domainbase.util.Result
import com.namasoft.modules.supplychain.domain.details.ItemDimensionsDetail
import com.namasoft.modules.supplychain.domain.details.StockTransferLine
import com.namasoft.modules.supplychain.domain.entities.InvItem
import com.namasoft.modules.supplychain.domain.entities.StockTransfer
import com.namasoft.modules.supplychain.domain.valueobjects.ItemDimensions
import com.namasoft.modules.supplychain.domain.valueobjects.ItemDimensionsData
import com.namasoft.modules.supplychain.domain.valueobjects.ItemSpecificDimensions

public class EALearnDefaultLocatorFromStockTransfer implements EntityAction<StockTransfer> {
    @Override
    Result doAction(StockTransfer doc, LongTextDF... parameters) {
        Result result = Result.createAccumulatingResult();
        for (StockTransferLine l : doc.getDetails()) {

            def item = l.getItem().getItem()
            def detail = item.getDetails().stream().filter({
                it.getItemDimensions() != null && it.getItemDimensions().getSpecificDimensions() != null && ObjectChecker.areEqual(it.getItemDimensions().getSpecificDimensions().getWarehouse(), l.getToWarehouse())
            }).findFirst().orElse(null);
            if (detail != null && ObjectChecker.areEqual(detail.getItemDimensions().getSpecificDimensions().getLocator(), l.getToLocator()))
                continue;
            item.startEditing().addToAccumulatingResult(result);
            if (detail == null) {
                detail = new ItemDimensionsDetail();
                item.getDetails().add(detail);
                detail.setItemDimensions(new ItemDimensions());
                detail.getItemDimensions().setSpecificDimensions(new ItemSpecificDimensions());
                detail.setData(new ItemDimensionsData());
            } else {
                detail = EntityDetailLine.findById(item.getDetails(), detail.getId());
            }
            detail.getItemDimensions().getSpecificDimensions().setWarehouse(l.getToWarehouse());
            detail.getItemDimensions().getSpecificDimensions().setLocator(l.getToLocator());
            detail.setDefaultLocator(BooleanDF.TRUE());
            detail.getData().setDesirable(BooleanDF.TRUE());
            EntityMediator.commitFromBusinessAction(item).addToAccumulatingResult(result);
        }
        return result;
    }

    @Override
    String describe() {
        return "Stock Transfer: for every line, records the line's to locator as the item's default locator in its to warehouse. " +
                "The item's Details grid gets a line for that warehouse (or its existing line is updated) with the locator, " +
                "the default locator box ticked and Desirable ticked, and the item is saved. Items whose line for that warehouse " +
                "already has the same locator are not saved again. Attach it to the Post Commit event of Stock Transfer. Parameter 1 is not used.";
    }

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

The opening stock script:

groovy
package com.namasoft.modules.supplychain.domain.utils.plugnplay.groovy

import com.namasoft.common.utilities.ObjectChecker
import com.namasoft.infra.domainbase.common.detail.EntityDetailLine
import com.namasoft.infra.domainbase.datafields.BooleanDF
import com.namasoft.infra.domainbase.datafields.LongTextDF
import com.namasoft.infra.domainbase.entity.base.EntityAction
import com.namasoft.infra.domainbase.entity.base.EntityMediator
import com.namasoft.infra.domainbase.util.Result
import com.namasoft.modules.supplychain.domain.details.ItemDimensionsDetail
import com.namasoft.modules.supplychain.domain.details.OpeningStockLine
import com.namasoft.modules.supplychain.domain.entities.OpeningStockDocument
import com.namasoft.modules.supplychain.domain.valueobjects.ItemDimensions
import com.namasoft.modules.supplychain.domain.valueobjects.ItemDimensionsData
import com.namasoft.modules.supplychain.domain.valueobjects.ItemSpecificDimensions

public class EALearnDefaultLocatorFromOpeningStock implements EntityAction<OpeningStockDocument> {
    @Override
    Result doAction(OpeningStockDocument doc, LongTextDF... parameters) {
        Result result = Result.createAccumulatingResult();
        for (OpeningStockLine l : doc.getDetails()) {

            def item = l.getItem().getItem()
            def detail = item.getDetails().stream().filter({
                it.getItemDimensions() != null && it.getItemDimensions().getSpecificDimensions() != null && ObjectChecker.areEqual(it.getItemDimensions().getSpecificDimensions().getWarehouse(), l.getSpecificDimensions().getWarehouse())
            }).findFirst().orElse(null);
            if (detail != null && ObjectChecker.areEqual(detail.getItemDimensions().getSpecificDimensions().getLocator(), l.getSpecificDimensions().getLocator()))
                continue;
            item.startEditing().addToAccumulatingResult(result);
            if (detail == null) {
                detail = new ItemDimensionsDetail();
                item.getDetails().add(detail);
                detail.setItemDimensions(new ItemDimensions());
                detail.getItemDimensions().setSpecificDimensions(new ItemSpecificDimensions());
                detail.setData(new ItemDimensionsData());
            } else {
                detail = EntityDetailLine.findById(item.getDetails(), detail.getId());
            }
            detail.getItemDimensions().getSpecificDimensions().setWarehouse(l.getSpecificDimensions().getWarehouse());
            detail.getItemDimensions().getSpecificDimensions().setLocator(l.getSpecificDimensions().getLocator());
            detail.setDefaultLocator(BooleanDF.TRUE());
            EntityMediator.commitFromBusinessAction(item).addToAccumulatingResult(result);
        }
        return result;
    }

    @Override
    String describe() {
        return "Opening Stock Document: for every line, records the line's locator as the item's default locator in the line's warehouse. " +
                "The item's Details grid gets a line for that warehouse (or its existing line is updated) with the locator and " +
                "the default locator box ticked, and the item is saved. Items whose line for that warehouse already has the same " +
                "locator are not saved again. Attach it to the Post Commit event of Opening Stock Document. Parameter 1 is not used.";
    }

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