Add Free Lines From the References on Each Sales Line
This Groovy script lets the user type a line's free goods on the line itself. On each sales line, the user picks up to three free items in Reference 1, Reference 2 and Reference 3 and enters their quantities in Number 1, Number 2 and Number 3. When the document is saved, each of those becomes a free line placed right under the line it belongs to.
Customer-specific example
This script was written for one customer's setup. It is hard-wired to these line fields; adapt it before you use it elsewhere:
- Reference 1, Reference 2 and Reference 3 hold the free items. A reference that points to anything other than an item is ignored.
- Number 1, Number 2 and Number 3 hold the matching quantities, in the free item's base unit. A reference with an empty or zero quantity is ignored.
| Class name | EAAddFreeLinesFromLineReferences |
| Script | EAAddFreeLinesFromLineReferences.groovy |
| Runs on | Sales documents: sales order, sales invoice and the like. Target action PreUpdateCalculatedFields. |
| Uses | No parameters. Leave Parameter 1 empty. |
| Shipped as | Source to paste. It is not built into the system. |
When to use it
The system's own free-item offers work from rules set up in advance. Some sales teams instead agree the free goods per order: "buy two air conditioners and get three box files free". This script lets the person entering the order record that deal on the line, without a rule and without adding and linking the free lines by hand.
How it works
- It goes through the lines that are not free. Lines already marked Free Item are skipped.
- It reads the three references. For each of Reference 1 to Reference 3 that points to an item and has a quantity in the matching Number field, it prepares one free line.
- It reuses the line's existing free lines. Free lines that the script added to this line on an earlier save are linked to it, so they are updated in place rather than added again. New ones are created only when more are needed.
- It fills each free line. The free line gets the item, the quantity in the item's base unit, Free Item ticked and an empty price. It is placed right after the line it belongs to.
- The document then calculates as usual. Because the script runs on PreUpdateCalculatedFields, the free lines are in place before the document works out its totals.
Setting it up
- Open Administration → Display Customization → Entity Flow and create a flow whose target type is the sales document to cover (for example Sales Order).
- In the Details grid, add a line with Target Action set to PreUpdateCalculatedFields, and paste the whole script into its Groovy Script column. Leave Class Name empty: it is filled in when you save.
- Leave all parameters empty, and save the flow.
- Make sure Reference 1 to Reference 3 and Number 1 to Number 3 are visible on the document's lines, so users can fill them.
Example
A sales order line sells 2 units of an air conditioner. On that line the user sets Reference 1 to the item OFF0017 with Number 1 = 3, and Reference 2 to the item OFF0018 with Number 2 = 1. After saving, the order has three lines: the air conditioner, then a free line of 3 units of OFF0017, then a free line of 1 unit of OFF0018, both with a zero price. Changing Number 1 to 5 and saving again updates the first free line to 5 units instead of adding another one.
The script
package com.namasoft.modules.supplychain.domain.utils.plugnplay.groovy
import com.namasoft.common.Pair
import com.namasoft.common.utilities.CollectionsUtility
import com.namasoft.common.utilities.ObjectChecker
import com.namasoft.infra.domainbase.datafields.BooleanDF
import com.namasoft.infra.domainbase.datafields.DecimalDF
import com.namasoft.infra.domainbase.datafields.LongTextDF
import com.namasoft.infra.domainbase.entity.base.EntityAction
import com.namasoft.infra.domainbase.entity.generic.GenericReference
import com.namasoft.infra.domainbase.util.Result
import com.namasoft.modules.basic.domain.valueobjects.InvoiceLineMoney
import com.namasoft.modules.supplychain.domain.details.SalesLine
import com.namasoft.modules.supplychain.domain.entities.InvItem
import com.namasoft.modules.supplychain.domain.entities.SalesDocument
import com.namasoft.modules.supplychain.domain.valueobjects.InvItemRef
import com.namasoft.modules.supplychain.domain.valueobjects.UserQuantity
import java.util.stream.Collectors
public class EAAddFreeLinesFromLineReferences implements EntityAction<SalesDocument> {
@Override
Result doAction(SalesDocument doc, LongTextDF... parameters) {
Result result = Result.createAccumulatingResult();
List<SalesLine> lines = doc.getDetails();
for (int i = lines.size() - 1; i >= 0; i--) {
if (i >= lines.size())
continue;
SalesLine line = lines.get(i)
if (BooleanDF.isTrue(line.getFreeLine()))
continue;
List<Pair<InvItem, DecimalDF>> items = new ArrayList<>();
List<Pair<GenericReference, DecimalDF>> refs = Arrays.asList(Pair.of(line.getRef1(), line.getN1()), Pair.of(line.getRef2(), line.getN2()), Pair.of(line.getRef3(), line.getN3()));
for (Pair<GenericReference, DecimalDF> ref : refs) {
if (GenericReference.toReal(ref.getX()) instanceof InvItem && DecimalDF.isNotEmptyOrZero(ref.getY()))
items.add(new Pair<>(ref.getX().toReal(), ref.getY()));
}
List<SalesLine> subLines = lines.stream().filter({ ObjectChecker.areEqual(it.getMasterRowId(), line.getId()) }).collect(Collectors.toList());
lines.removeAll(subLines);
CollectionsUtility.makeSecondSameSize(items, subLines, { doc.createLine() });
for (int j = 0; j < items.size(); j++) {
Pair<InvItem, DecimalDF> pair = items.get(j);
SalesLine l = subLines.get(j);
l.setItem(InvItemRef.from(pair.getX()));
l.setQuantity(UserQuantity.createQuantity(pair.getX(), pair.getY()));
l.setMasterRowId(line.getId());
l.setFreeLine(BooleanDF.TRUE());
l.setPrice(new InvoiceLineMoney())
l.updateNulls();
}
lines.addAll(i + 1, subLines);
}
return result;
}
@Override
String describe() {
return "Use it on PreUpdateCalculatedFields of a sales document. For every line that is not a free line, each of Ref 1, Ref 2 " +
"and Ref 3 that points to an item, with a quantity in N1, N2 or N3 respectively, becomes a free line placed right after " +
"that line. The free line carries the item, that quantity in the item's base unit and an empty price, and is linked to " +
"its line, so saving again updates the same free lines instead of adding new ones. Parameter 1 is not used.";
}
@Override
List<String> columnNames() {
return Arrays.asList("Not used - leave empty");
}
}Related
- EAGroovyAction: how Groovy scripts are attached to entity flows.