Skip to content

Commit e24414c

Browse files
committed
Initial check-in of Auto Insurance constraint model
1 parent 978d1fd commit e24414c

1 file changed

Lines changed: 350 additions & 0 deletions

File tree

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
/* =====================================================
2+
* Gold Standard CML Constraint Model for Auto Silver Product
3+
* =====================================================
4+
A product configuration constraints CML file for Auto Silver Product
5+
covering use cases of:
6+
- Base constraint
7+
- Multi-instance constraint
8+
- Require coverage constraint
9+
- Exclude coverage constraint
10+
- Cardinality constraint
11+
- Parent cardinality constraint
12+
- Cross Product constraint
13+
- Grandchild products constraint
14+
- Siblings products constraint
15+
*/
16+
17+
/*
18+
Get Quote/Sales Transaction Level Attribute from Context Definition, such as User Profile, Quote Start Date, etc.
19+
*/
20+
@(contextPath = "SalesTransaction.UserProfile", attributeSource = "ST")
21+
extern string UserProfile;
22+
23+
/*
24+
Root Product Bundle: Auto Silver
25+
@closeRelation = true: tell the constraint engine not to add any new instances in the relation, but the ones added by users or require rules are allowed.
26+
@propagateUp = true: tell the constraint engine only propagate from child to parent for aggregation function such as sum, max, count, etc.
27+
@sequence = 1: Indicates the sequence in which the variables are configured. The constraint engine assigns the values based on the sequence, with the lowest in the
28+
sequence assigned first. (only effective within a type)
29+
30+
Multi-instance use case: using aggregate functions for attributes from child relations (see "relation auto : Vehicle").
31+
If there's only 1 instance allowed for this relation, then OK to get attributes without aggregate functions
32+
*/
33+
type AutoSilver {
34+
@(closeRelation = true, propagateUp = true, sequence = 1)
35+
relation auto : Vehicle {
36+
maxAutoValue = max(Auto_Value);
37+
minAutoYear = min(Year);
38+
maxDriverAccPoint1 = max(maxDriverAccPoint);
39+
autoHasAntiTheft = count(Has_Anti_Theft > 0);
40+
}
41+
42+
@(sequence = 2)
43+
relation bodilyinjurypropertydamage : BodilyInjuryPropertyDamage[0..1];
44+
45+
@(sequence = 3)
46+
relation medicalpayments : MedicalPayments[0..1] {
47+
medicalLimit = Limit;
48+
medicalDeductible = Deductible;
49+
medicalInputUnitPrice = inputUnitPrice;
50+
}
51+
52+
/*
53+
Get Quote Line Item/Sales Transaction Item Level Attribute from Context Definition, such as Item Total Price, Item Discount Amount, etc.
54+
tagName should be the same as Attribute Tag
55+
*/
56+
@(tagName = "ItemTotalPrice")
57+
decimal(2) totalPrice;
58+
59+
/*
60+
Constraint 1: A bundle with the most expensive car over $50,000 and the oldest car before 2020 must have Medical Payment Coverage with $2000 limit
61+
62+
Multi-instance Constraint
63+
Require coverage constraint
64+
Cross Product constraint
65+
*/
66+
boolean constraint1 = auto.maxAutoValue >= 50000 && auto.minAutoYear < 2020;
67+
require(constraint1, medicalpayments[MedicalPayments], "Auto add Medical Payments");
68+
constraint(constraint1 && medicalpayments[MedicalPayments] > 0 -> medicalpayments[MedicalPayments].Limit == 2000, "Medical coverage set to $2000 for older high-value vehicles");
69+
70+
/*
71+
Constraint 5: A bundle of at least one car doesn't have Anti-Theft, at least one driver has accident point greater than 5, no medical payment coverage, and total price for product bundle over $100:
72+
- Must have BIPD coverage (bodily injury & property damage)
73+
- Attribute: Property damage per Accident Limit of BIPD must be hidden (see under type BodilyInjuryPropertyDamage)
74+
- Value: $2000 of Bodily Injury Per Accident Limit of BIPD must be hidden (see under type BodilyInjuryPropertyDamage)
75+
76+
@abort = true: preventing the constraint engine from recursively backtracking and causing timeout, instead, surface configuration error message when encountering.
77+
78+
Multi-instance Constraint
79+
Require coverage constraint
80+
Cardinality constraint
81+
Parent cardinality constraint
82+
Cross Product constraint
83+
Grandchild products constraint
84+
Siblings products constraint
85+
*/
86+
boolean autoCondition = auto[Vehicle] > 0 && !auto.autoHasAntiTheft;
87+
boolean driverCondition = auto.maxDriverAccPoint1 > 5;
88+
boolean totalPriceCondition = totalPrice > 10;
89+
boolean constraint5 = autoCondition && driverCondition && totalPriceCondition && medicalpayments[MedicalPayments] == 0;
90+
@(abort = true)
91+
require(constraint5, bodilyinjurypropertydamage[BodilyInjuryPropertyDamage], "BIPD is required when Auto IsElectricVehicle and Antitheft is false and Driver accident points > 5 and Collision is selected and MedicalPayments is NOT selected");
92+
93+
94+
/*
95+
Constraint 6: A bundle with Medical Payment coverage with limit $1000, opearted by standard user, and the unit price for medical payment is over $220:
96+
- Must have BIPD with Bodily Injury Per Person Limit $1000
97+
98+
Require coverage constraint
99+
Cardinality constraint
100+
Cross Product constraint
101+
Siblings products constraint
102+
*/
103+
boolean constraint6 = medicalpayments[MedicalPayments] == 1 && medicalpayments.medicalDeductible == 500 && UserProfile == "Standard User" && medicalpayments.medicalInputUnitPrice > 220;
104+
require(constraint6, bodilyinjurypropertydamage[BodilyInjuryPropertyDamage], "BIPD is required when MedicalPayments is selected at 1k limit");
105+
constraint(constraint6 && bodilyinjurypropertydamage[BodilyInjuryPropertyDamage] -> bodilyinjurypropertydamage[BodilyInjuryPropertyDamage].Bodily_Injury_Per_Person_Limit == 1000);
106+
}
107+
108+
/*
109+
Product Classification: Auto
110+
111+
@configurable = false: prevent the engine from modifying/assigning the value of an attribute.
112+
Best Practices for variable initialization:
113+
- for int variables, if using picklist possible, using picklist. If not possible, please add domain (possible values).
114+
- for picklist variables, set default value if possible.
115+
- for variables that are not supposed to be modified by the constraint engine, add configurable = false annotation.
116+
*/
117+
type Auto {
118+
@(configurable = false)
119+
decimal(2) Auto_Value;
120+
121+
int Year = [1980..2026];
122+
123+
@(configurable = false)
124+
string Colour;
125+
126+
@(configurable = false)
127+
string Make;
128+
129+
@(configurable = false)
130+
int License_Number;
131+
132+
string License_State;
133+
134+
@(configurable = false)
135+
string Model;
136+
137+
boolean Is_Electric_Vehicle;
138+
139+
boolean Has_Anti_Theft;
140+
141+
string AssetRecordName;
142+
143+
}
144+
145+
/*
146+
Product Bundle: Auto
147+
*/
148+
type Vehicle : Auto {
149+
int maxDriverAccPoint = driver.maxDriverAccPoint;
150+
151+
@(sequence = 4)
152+
relation collision : Collision[0..1];
153+
154+
@(sequence = 2)
155+
relation comprehensive : Comprehensive[0..1];
156+
157+
@(sequence = 3)
158+
relation uninsuredMotorist : UninsuredMotorist[0..1];
159+
160+
@(closeRelation = true, propagateUp = true, sequence = 1)
161+
relation driver : AutoDriver[0..5] {
162+
maxDriverAccPoint = max(Driver_Accident_Points);
163+
}
164+
165+
/*
166+
Constraint 2: Car is newer than 2023 must have Collision Coverage with $5000 limit.
167+
168+
Require coverage constraint
169+
Cross Product constraint
170+
*/
171+
boolean constraint2 = Year > 2023;
172+
constraint(constraint2 -> collision[Collision], "auto add collision coverage");
173+
constraint(constraint2 && collision[Collision] > 0 -> collision[Collision].Limit == 5000, "set collision limit to 5000");
174+
175+
/*
176+
Constraint 3: Car is older than 2020 and Collision Coverage is selected with $200 deductible MUST NOT have Uninsured Motorist Coverage.
177+
178+
Exlude coverage constraint
179+
Cross Product constraint
180+
*/
181+
boolean constraint3 = collision[Collision] > 0 && collision[Collision].Deductible == 200 && Year < 2020;
182+
exclude(constraint3, uninsuredMotorist[UninsuredMotorist]);
183+
184+
require(collision[Collision] > 0 && collision[Collision].Deductible == 200 && Year < 2020 && UserProfile == "Standard User", comprehensive[Comprehensive]);
185+
message(Auto_Value > 500000, "Error: Insurance cant be provided","Error");
186+
message(Auto_Value == null , "Error: Auto value cant be null","Error");
187+
188+
}
189+
190+
/*
191+
Product Classification: Driver
192+
Best Practices:
193+
*/
194+
type Driver {
195+
int Driver_Accident_Points = [0..10];
196+
197+
int Driver_MVR_Points;
198+
199+
string Driving_License;
200+
201+
int Age_First_Licensed = [0..100];
202+
203+
//int Contact_Number;
204+
205+
@(configurable = false)
206+
string E_Mail;
207+
208+
@(configurable = false)
209+
string State;
210+
211+
@(configurable = false)
212+
int Age = [0..100];
213+
214+
@(configurable = false)
215+
string First_Name;
216+
217+
@(configurable = false)
218+
string Last_Name;
219+
220+
/*
221+
Constraint 4: Driver Age and First Licensed Age must be equal or greater than 16.
222+
223+
Base constraint
224+
*/
225+
message(Age_First_Licensed < 16, "Don’t know who gave you license to driver before 16, legally!", "Warning");
226+
message(Age < 16, "Error”: Driver is underaged to be added to the quote", "Error");
227+
228+
}
229+
230+
/*
231+
Product: Driver
232+
*/
233+
type AutoDriver : Driver;
234+
235+
/*
236+
Product: UninsuredMotorist
237+
*/
238+
@(split = false)
239+
type UninsuredMotorist {
240+
int Deductible = [0, 50, 100, 200, 500];
241+
242+
int Property_Damage_Per_Accident_Limit = [500, 1000, 1500, 2000];
243+
244+
int Bodily_Injury_Per_Person_Limit = [500, 1000, 1500, 2000];
245+
246+
int Bodily_Injury_Per_Accident_Limit = [500, 1000, 1500, 2000];
247+
248+
int Limit = [1000, 2000, 5000, 10000, 25000, 50000];
249+
250+
int Number_Of_Days = [1, 3, 5, 10, 15, 30];
251+
252+
253+
}
254+
255+
/*
256+
Product: Collision
257+
*/
258+
@(split = false)
259+
type Collision {
260+
@(domainComputation = false)
261+
int Deductible = [0, 50, 100, 200, 500];
262+
263+
@(domainComputation = false)
264+
int Property_Damage_Per_Accident_Limit = [500, 1000, 1500, 2000];
265+
266+
@(domainComputation = false)
267+
int Bodily_Injury_Per_Person_Limit = [500, 1000, 1500, 2000];
268+
269+
@(domainComputation = false)
270+
int Bodily_Injury_Per_Accident_Limit = [500, 1000, 1500, 2000];
271+
272+
@(defaultValue = "1000", domainComputation = false)
273+
int Limit = [1000, 2000, 5000, 10000, 25000, 50000];
274+
275+
int Number_Of_Days = [1, 3, 5, 10, 15, 30];
276+
277+
}
278+
279+
/*
280+
Product: Bodily Injury Property Damage
281+
*/
282+
@(split = false)
283+
type BodilyInjuryPropertyDamage {
284+
@(defaultValue = "100", domainComputation = false)
285+
int Deductible = [0, 50, 100, 200, 500];
286+
287+
@(defaultValue = "1000", domainComputation = false)
288+
int Bodily_Injury_Per_Person_Limit = [500, 1000, 1500, 2000];
289+
290+
@(defaultValue = "1000", domainComputation = false)
291+
int Property_Damage_Per_Accident_Limit = [500, 1000, 1500, 2000];
292+
293+
@(defaultValue = "1000", domainComputation = false)
294+
int Bodily_Injury_Per_Accident_Limit = [500, 1000, 1500, 2000];
295+
296+
@(defaultValue = "1000", domainComputation = false)
297+
int Limit = [1000, 2000, 5000, 10000, 25000, 50000];
298+
299+
int Number_Of_Days = [1, 3, 5, 10, 15, 30];
300+
/*
301+
Constraint 5: A bundle of at least one car doesn't have Anti-Theft, at least one driver has accident point greater than 5, no medical payment coverage, and total price for product bundle over $100:
302+
- Must have BIPD coverage (see under AutoSilver)
303+
- Attribute: Property damage per Accident Limit of BIPD must be hidden
304+
- Value: $2000 of Bodily Injury Per Accident Limit of BIPD must be hidden
305+
*/
306+
boolean rootconstraint5 = parent(constraint5);
307+
rule(rootconstraint5, "hide", "attribute", "Property_Damage_Per_Accident_Limit");
308+
rule(rootconstraint5, "hide", "attribute", "Bodily_Injury_Per_Accident_Limit","value", 2000);
309+
310+
}
311+
312+
/*
313+
Product: Medical Payments
314+
@split = false: there is only one instance in the relationship.
315+
*/
316+
@(split = false)
317+
type MedicalPayments {
318+
@(defaultValue = "100", domainComputation = false)
319+
int Deductible = [0, 50, 100, 200, 500];
320+
321+
int Property_Damage_Per_Accident_Limit = [500, 1000, 1500, 2000];
322+
323+
int Bodily_Injury_Per_Person_Limit = [500, 1000, 1500, 2000];
324+
325+
int Bodily_Injury_Per_Accident_Limit = [500, 1000, 1500, 2000];
326+
327+
@(defaultValue = "1000", domainComputation = false)
328+
int Limit = [1000, 2000, 5000, 10000, 25000, 50000];
329+
330+
int Number_Of_Days = [1, 3, 5, 10, 15, 30];
331+
332+
@(tagName = "InputUnitPrice")
333+
decimal(2) inputUnitPrice;
334+
335+
}
336+
337+
/*
338+
Product: Comprehensive
339+
*/
340+
@(split = false)
341+
type Comprehensive {
342+
@(defaultValue = "100", domainComputation = false)
343+
int Deductible = [0, 50, 100, 200, 500];
344+
345+
@(defaultValue = "1000", domainComputation = false)
346+
int Limit = [1000, 2000, 5000, 10000, 25000, 50000];
347+
348+
int Number_Of_Days = [1, 3, 5, 10, 15, 30];
349+
350+
}

0 commit comments

Comments
 (0)