diff --git a/conf/nodes.xml b/conf/nodes.xml
index e327af1..5e55c72 100644
--- a/conf/nodes.xml
+++ b/conf/nodes.xml
@@ -16,10 +16,14 @@
10
MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE
-
+
1500
MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE
+
+ 1000
+ MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE
+
250
MEAT SALE;VEGETABLE SALE;FRUIT SALE
diff --git a/conf/scenarios.xml b/conf/scenarios.xml
index 68f28ef..d08dd00 100644
--- a/conf/scenarios.xml
+++ b/conf/scenarios.xml
@@ -10,15 +10,16 @@
generate
consume
doaction
-doaction
-sendreq
+sell
+buy
pass
-->
generate
- sendreq SALE FRUIT jablko
+ pass
+ sell FRUIT jablko
\ No newline at end of file
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java
index 0f0b984..46d8095 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java
@@ -1,6 +1,7 @@
package cz.cvut.fel.sit.omo.foodchain.channel;
import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase;
+import cz.cvut.fel.sit.omo.foodchain.operation.ProductTransaction;
import cz.cvut.fel.sit.omo.foodchain.operation.Transaction;
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
import cz.cvut.fel.sit.omo.foodchain.requirement.Requirement;
@@ -81,6 +82,10 @@ public abstract class ChannelBase implements Observable {
public void addTransaction(Transaction transaction)
{
this.transactions.add(transaction);
+ try {
+ ((ProductTransaction) transaction).getProduct().setStateToInTransit();
+ }
+ catch (Exception ignored) {}
}
public void disposeOf(Requirement requirement) { this.requirements.remove(requirement); }
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java
index d52163b..1fbd2a3 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java
@@ -61,10 +61,10 @@ public class ScenarioFactory
}
break;
case "sell":
- scenarioStep = new SendRequirementStep(node, TransactionType.SALE, ProductType.valueOf(parts[1]), parts[2], Double.parseDouble(parts[3]));
+ scenarioStep = new SendRequirementStep(node, TransactionType.SALE, ProductType.valueOf(parts[1]), parts[2]);
break;
case "buy":
- scenarioStep = new SendRequirementStep(node, TransactionType.PURCHASE, ProductType.valueOf(parts[1]), parts[2]);
+ scenarioStep = new SendRequirementStep(node, TransactionType.PURCHASE, ProductType.valueOf(parts[1]), parts[2], Double.parseDouble(parts[3]));
break;
case "pass":
scenarioStep = new PassStep();
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java
index 36cef45..d94670a 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java
@@ -11,6 +11,7 @@ public class Customer extends BuyerNodeBase {
super(startMoney);
allowedSeller = NodeType.Distributor;
allowedPurchaser = NodeType.None;
+ this.nodeType = NodeType.Customer;
}
public void consumeProduct() {
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java
index f3669d7..cf398e0 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java
@@ -9,5 +9,6 @@ public class Distributor extends RetailerNodeBase {
super(startMoney);
allowedSeller = NodeType.Seller;
allowedPurchaser = NodeType.Customer;
+ this.nodeType = NodeType.Distributor;
}
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java
index c65ffcf..76bf758 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java
@@ -5,16 +5,23 @@ import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType;
import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType;
import cz.cvut.fel.sit.omo.foodchain.product.Product;
+import javax.naming.InsufficientResourcesException;
+
public class Farmer extends SellerNodeBase {
public Farmer(double startMoney) {
super(startMoney);
allowedSeller = NodeType.None;
allowedPurchaser = NodeType.Processor;
+ this.nodeType = NodeType.Farmer;
}
public void generateProduct(Product product) {
storeProduct(product);
- createRequirement(TransactionType.SALE, product.getProductType(), product.getName(), product.getPrice());
+ try {
+ createRequirement(TransactionType.SALE, product.getProductType(), product.getName(), product.getPrice());
+ } catch (InsufficientResourcesException e) {
+ System.err.println(e.getMessage());
+ }
}
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java
index 1cb68a9..38237e4 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java
@@ -9,5 +9,6 @@ public class Processor extends RetailerNodeBase {
super(startMoney);
allowedSeller = NodeType.Farmer;
allowedPurchaser = NodeType.Seller;
+ this.nodeType = NodeType.Processor;
}
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java
index 47b9c5b..c2003d1 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java
@@ -9,5 +9,6 @@ public class Seller extends RetailerNodeBase {
super(startMoney);
allowedSeller = NodeType.Processor;
allowedPurchaser = NodeType.Distributor;
+ this.nodeType = NodeType.Seller;
}
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java
index 7490577..08f340c 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java
@@ -27,21 +27,24 @@ public class NodeBase implements ChannelObserver {
private final List refusedTransactions;
private MonetaryAmount money;
+
+ protected NodeType nodeType;
protected NodeType allowedSeller;
protected NodeType allowedPurchaser;
public NodeBase() {
- subscribedChannels = new HashMap<>();
- products = new LinkedList<>();
- refusedTransactions = new LinkedList<>();
- money = Money.of(0, "USD");
+ this.nodeType = NodeType.None;
+ this.subscribedChannels = new HashMap<>();
+ this.products = new LinkedList<>();
+ this.refusedTransactions = new LinkedList<>();
+ this.money = Money.of(0, "USD");
}
public NodeBase(double m) {
- subscribedChannels = new HashMap<>();
- products = new LinkedList<>();
- refusedTransactions = new LinkedList<>();
- money = Money.of(m, "USD");
+ this.subscribedChannels = new HashMap<>();
+ this.products = new LinkedList<>();
+ this.refusedTransactions = new LinkedList<>();
+ this.money = Money.of(m, "USD");
}
@@ -84,6 +87,7 @@ public class NodeBase implements ChannelObserver {
public void receiveTransaction(ProductTransaction transaction) {
if (validateSignature(transaction)) {
+ transaction.getProduct().setStateToReadyForReception();
transaction.endTransaction();
sendTransaction(transaction.getProduct().getPrice(), transaction.getNodeCreator(), transaction);
@@ -114,20 +118,32 @@ public class NodeBase implements ChannelObserver {
.findAny().ifPresent(channel -> channel.addRequirement(req));
}
- public void createRequirement(TransactionType tType, ProductType pType, String pName, MonetaryAmount price) {
+ public void createRequirement(TransactionType tType, ProductType pType, String pName, MonetaryAmount price) throws InsufficientResourcesException {
+ if (price == null) {
+ try {
+ price = getProductFromStorage(pName, pType).getPrice();
+ }
+ catch (NullPointerException e) {
+ throw new InsufficientResourcesException("product unavailable");
+ }
+ }
Requirement req = new Requirement(this, tType, pType, pName, price);
subscribedChannels.keySet().stream()
.filter(ch -> ch.getProductType().equals(pType))
.findAny().ifPresent(channel -> channel.addRequirement(req));
}
- public void acceptRequirement(Requirement req) {
- System.out.println(this.getClass().getSimpleName() + " accepted " + req.toString());
+ public void acceptRequirement(Requirement req) throws InsufficientResourcesException {
+ System.out.println(this.nodeType.toString() + " accepted " + req.toString());
if (req.getTransactionType() == TransactionType.SALE) {
createRequirement(TransactionType.PURCHASE, req.getProductType(), req.getProductName(), req.getPrice());
}
else {
- sendTransaction(getProductFromStorage(req.getProductName(), req.getProductType()), req.getCreator());
+ if (req.getPrice().isGreaterThanOrEqualTo(getProductFromStorage(req.getProductName(), req.getProductType()).getPrice().multiply(0.9))) {
+ getProductFromStorage(req.getProductName(), req.getProductType()).setPrice(req.getPrice());
+ sendTransaction(getProductFromStorage(req.getProductName(), req.getProductType()), req.getCreator());
+ }
+ else createRequirement(TransactionType.SALE, req.getProductType(), req.getProductName(), req.getPrice());
}
}
@@ -143,13 +159,27 @@ public class NodeBase implements ChannelObserver {
}
- public void doAction(ProductOperationType action, Product product) {
- Action actionProcess = new Action(this, product, action);
+ /**
+ * Proceed specific type of action on provided product if its possible.
+ * @param action type of product operation to do
+ * @param product product to proceed
+ */
+ public void doAction(ProductOperationType action, Product product) throws IllegalCallerException
+ {
+ if(action.getNode().equals(this.nodeType))
+ new Action(this, product, action);
+ else
+ throw new IllegalCallerException("! IllegalCallerException in NodeBase. " + this.nodeType.toString() + " cannot do action available only for "+action.getNode());
}
- public void doAction(ProductOperationType action) {
- //create new action
+ /**
+ * Calls specific ProductOperation on each product in stock
+ * @param action ProductOperationType
+ */
+ public void doAction(ProductOperationType action)
+ {
+ this.products.forEach(t -> new Action(this, t, action));
}
@@ -188,11 +218,11 @@ public class NodeBase implements ChannelObserver {
}
boolean senderPurchaserCheck(Requirement req) {
- String simpleName = req.getCreator().getClass().getSimpleName();
+ NodeType creatorType = req.getCreator().nodeType;
return !req.getCreator().equals(this) &&
- (((allowedSeller == NodeType.valueOf(simpleName) || allowedSeller == NodeType.All) && (req.getTransactionType() == TransactionType.SALE)) ||
- ((allowedPurchaser == NodeType.valueOf(simpleName) || allowedPurchaser == NodeType.All) && req.getTransactionType() == TransactionType.PURCHASE));
+ (((allowedSeller == creatorType || allowedSeller == NodeType.All) && (req.getTransactionType() == TransactionType.SALE)) ||
+ ((allowedPurchaser == creatorType || allowedPurchaser == NodeType.All) && req.getTransactionType() == TransactionType.PURCHASE));
}
boolean transactionSubscriptionCheck(Requirement requirement, ChannelBase channel) {
@@ -217,13 +247,17 @@ public class NodeBase implements ChannelObserver {
@Override
public void update(Requirement requirement, ChannelBase channel) {
if (senderPurchaserCheck(requirement) && transactionSubscriptionCheck(requirement, channel) && requirementCheck(requirement)) {
- channel.disposeOf(requirement);
- acceptRequirement(requirement);
+ try {
+ acceptRequirement(requirement);
+ channel.disposeOf(requirement);
+ } catch (InsufficientResourcesException e) {
+ System.err.println(e.getMessage());
+ }
}
}
public void tick() {
receiveTransactions();
- System.out.println(this.getClass().getSimpleName() + ": " + money.getNumber());
+ //System.out.println(this.getClass().getSimpleName() + ": " + money.getNumber());
}
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java
index 8e35694..7733967 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java
@@ -17,7 +17,8 @@ public class Action extends OperationBase {
lastOperation = product.getCurrentOperation();
duration = type.getDuration();
product.setCurrentOperation(this);
- product.setStateToReadyForDispatch();
+ product.setStateToInAction();
+ System.out.println(toString());
}
private void endAction() {
@@ -45,4 +46,13 @@ public class Action extends OperationBase {
public ProductOperationType getType() {
return type;
}
+
+ @Override
+ public String toString() {
+ return "Action{" +
+ ", product=" + product +
+ ", type=" + type +
+ ", duration=" + duration +
+ '}';
+ }
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java
index 030ce8f..594be25 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java
@@ -1,22 +1,52 @@
package cz.cvut.fel.sit.omo.foodchain.operation;
-public enum ProductOperationType {
+import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType;
- STORE_MEAT(10, -8);
+public enum ProductOperationType
+{
+ STORE_MEAT(NodeType.All, 20, -8),
+ STORE_FRUIT(NodeType.All, 8, 2),
+ STORE_VEGETABLE(NodeType.All, 10, 2),
+ STORE_OTHER(NodeType.All, 30, 21),
+ WRAP_INTO_GIFT_PACKAGE(NodeType.Seller, 1, -8),
+ UNWRAP(NodeType.All, 1, 21),
+ CUT_TO_PIECES(NodeType.All, 1, 21),
+
+ BOIL_MEAT(NodeType.All, 1, 21),
+ GRILL_MEAT(NodeType.All, 1, 21),
+ SMOKE_MEAT(NodeType.All, 1, 21),
+ DRY_MEAT(NodeType.All, 1, 21),
+
+ DRY_FRUIT(NodeType.All, 1, 21),
+ FREEZE_DRY_FRUIT(NodeType.All, 1, 21);
+
+
+ //todo add product type allowed for this action
+
+ private final NodeType node;
private final int duration;
private final int temperature;
- ProductOperationType(int duration, int temperature) {
+ ProductOperationType(NodeType node, int duration, int temperature)
+ {
+ this.node = node;
this.duration = duration;
this.temperature = temperature;
}
- public int getDuration() {
+ public int getDuration()
+ {
return duration;
}
- public int getTemperature() {
+ public int getTemperature()
+ {
return temperature;
}
+
+ public NodeType getNode()
+ {
+ return node;
+ }
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java
index b60b3cc..6252afd 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java
@@ -111,6 +111,17 @@ public class Product
throw new IllegalStateException("Cannot set state READY_FOR_RECEPTION. Product has not been in transit!");
}
+ /**
+ * Set current product state to IN_ACTION. Throws IllegalStateException if the product is not AVAILABLE.
+ */
+ public void setStateToInAction()
+ {
+ if(this.productState.equals(ProductState.AVAILABLE))
+ this.productState = ProductState.IN_ACTION;
+ else
+ throw new IllegalStateException("Cannot set state IN_ACTION. Product is not AVAILABLE!");
+ }
+
/*
public void setProductState(ProductState productState)
{
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java
index 2d7b4d1..906282e 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java
@@ -2,5 +2,5 @@ package cz.cvut.fel.sit.omo.foodchain.product;
public enum ProductState
{
- AVAILABLE, READY_FOR_DISPATCH, IN_TRANSIT, READY_FOR_RECEPTION;
+ AVAILABLE, READY_FOR_DISPATCH, IN_TRANSIT, READY_FOR_RECEPTION, IN_ACTION
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java
index 5e513cf..2caf0c6 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java
@@ -17,6 +17,8 @@ public class Requirement {
private final String productName;
private final MonetaryAmount price;
private int TTL;
+ private static int counter;
+ private int id;
public Requirement(NodeBase creator, TransactionType transactionType, ProductType productType, String productName, double price) {
this.creator = creator;
@@ -24,7 +26,8 @@ public class Requirement {
this.productType = productType;
this.productName = productName;
this.price = Money.of(price, "USD");
- TTL = 3;
+ this.TTL = 3;
+ this.id = counter++;
System.out.println(toString());
}
@@ -34,7 +37,8 @@ public class Requirement {
this.productType = productType;
this.productName = productName;
this.price = price;
- TTL = 3;
+ this.TTL = 3;
+ this.id = counter++;
System.out.println(toString());
}
@@ -67,7 +71,8 @@ public class Requirement {
@Override
public String toString() {
return "Requirement{" +
- "creator=" + creator.getClass().getSimpleName() +
+ "id=" + id +
+ ", creator=" + creator.getClass().getSimpleName() +
", transactionType=" + transactionType +
", productName='" + productName + '\'' +
", TTL=" + TTL +
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java
index 433376a..f934978 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java
@@ -22,11 +22,17 @@ public class DoActionStep extends ScenarioStep {
@Override
void execute() {
- if (product != null){
- nodeBase.doAction(productOperationType, product);
+ //todo maybe do a better error handling
+ try {
+ if (product != null) {
+ nodeBase.doAction(productOperationType, product);
+ }
+ else {
+ nodeBase.doAction(productOperationType);
+ }
}
- else {
- nodeBase.doAction(productOperationType);
+ catch (IllegalCallerException e) {
+ System.err.println(e.getMessage());
}
}
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java
index 862cc42..19e958f 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java
@@ -6,22 +6,25 @@ import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
import org.javamoney.moneta.Money;
import javax.money.MonetaryAmount;
+import javax.naming.InsufficientResourcesException;
public class SendRequirementStep extends ScenarioStep {
private final NodeBase node;
private final TransactionType tType;
private final ProductType pType;
private final String pName;
- private final MonetaryAmount pPrice;
+ private MonetaryAmount pPrice;
+ // sell
public SendRequirementStep(NodeBase node, TransactionType tType, ProductType pType, String pName) {
this.node = node;
this.tType = tType;
this.pType = pType;
this.pName = pName;
- this.pPrice = Money.of(0, "USD");
+ this.pPrice = null;
}
+ // buy
public SendRequirementStep(NodeBase node, TransactionType tType, ProductType pType, String pName, Double price) {
this.node = node;
this.tType = tType;
@@ -32,6 +35,10 @@ public class SendRequirementStep extends ScenarioStep {
@Override
void execute() {
- node.createRequirement(tType, pType, pName, pPrice);
+ try {
+ node.createRequirement(tType, pType, pName, pPrice);
+ } catch (InsufficientResourcesException e) {
+ System.err.println(e.getMessage());
+ }
}
}
diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java
index 7ccf9b7..862c908 100644
--- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java
+++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java
@@ -13,12 +13,12 @@ public class Ticker {
private static Timer timer;
public static void start() {
- timer = new Timer(500, actionEvent -> {
+ timer = new Timer(1000, actionEvent -> {
System.out.println("-----tick-----");
PoolDatabase db = FoodChain.getFactoryManager().getPoolDatabaseInstance();
boolean productBool = db.getProductPoolInstance().findAll().stream().filter(Product::tick).count() == 0; // change duration of action
- boolean scenarioBool = db.getScenarioPoolInstance().findAll().stream().filter(Scenario::tick).count() == 0; // do next step in scenario
boolean channelBool = db.getChannelPoolInstance().findAll().stream().filter(ChannelBase::tick).count() == 0; // change TTL of requirements
+ boolean scenarioBool = db.getScenarioPoolInstance().findAll().stream().filter(Scenario::tick).count() == 0; // do next step in scenario
db.getNodePoolInstance().findAll().forEach(n -> n.tick()); // receive transactions
if (channelBool && productBool && scenarioBool) stop();
});