Virtual Quote Root: Model Cross-Bundle Logic Using a Shared Transaction Parent

For transaction-level rules that span products that have no parent-child relationship, use a virtual quote as a transaction root pattern.

For transaction-level rules that span products that have no parent-child relationship, use a virtual quote as a transaction root pattern. Define a virtual type that exists only to act as the configuration root. Each independent bundle or standalone product hangs off it as a relation. Because the products share the virtual root as a common parent, a rule declared on the virtual root can reach across both subtrees to give cross-bundle interaction logic.

In this example, GeneratorSet is a bundle with its own Accessories child hierarchy, and InstallationKit is an independent standalone product. The require rule ties them together at the transaction level, so that any generator that includes accessories must also ship with an installation kit.

1// Child line inside the GeneratorSet bundle
2type Accessory;
3
4// An independent standalone product
5type InstallationKit;
6
7// The GeneratorSet bundle owns its own child hierarchy
8type GeneratorSet {
9    int requiredKW = [101..10000];
10    relation Accessories : Accessory[0..99];
11}
12
13// Virtual transaction root: never sold on its own. It exists only to
14// host cross-bundle rules by giving independent products a shared parent.
15type Quote {
16    relation generatorSet    : GeneratorSet[0..1];
17    relation installationKit : InstallationKit[0..1];
18
19    /**
20    * @Title Cross-Bundle Attach Rule
21    * When the GeneratorSet includes at least one Accessory, the
22    * transaction must also include exactly one Installation Kit.
23    */
24    require(
25        generatorSet.Accessories[Accessory] > 0,
26        installationKit[InstallationKit] == 1,
27        "An Installation Kit is required when the GeneratorSet includes accessories"
28    );
29}

generatorSet.Accessories[Accessory] > 0 is the condition, which reaches down into the subtree of GeneratorSet to count the Accessory lines. installationKit[InstallationKit] == 1 is the target, which acts on a completely separate branch of the transaction, forcing exactly one installation kit. The rule lives on Quote, not on GeneratorSet or InstallationKit, because only the shared root can see both branches at once. GeneratorSet and InstallationKit stay independent and sellable on their own, while the transaction-level relationship is layered on top only where they’re combined.