added second domain
This commit is contained in:
@@ -37,7 +37,7 @@ Structuring your code functional and brining more context to your object with, e
|
||||
|
||||
### Clean
|
||||
|
||||
Using clean architecture as architecture style combines perfectly with Domain-driven Design, because we completely focus on our domain.
|
||||
Using clean architecture as architecture style combines perfectly with Domain-driven Design, because we completely focus on our domain, by using the [Dependency Inversion Principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle).
|
||||
|
||||
Flexibility around your domain is the main focus I want to show you in this little example.
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"elements": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
"version": 419,
|
||||
"versionNonce": 1353777024,
|
||||
"version": 424,
|
||||
"versionNonce": 144857726,
|
||||
"isDeleted": false,
|
||||
"id": "Euc_Y36uu1tj7wSxPMAKo",
|
||||
"fillStyle": "hachure",
|
||||
@@ -25,40 +25,40 @@
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467138757,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "ufXZhHDFuihic0jU210X8",
|
||||
"type": "ellipse",
|
||||
"x": 257.6329680816313,
|
||||
"y": 579.0412908392208,
|
||||
"width": 481.53809559813783,
|
||||
"height": 481.53809559813783,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#1faf98",
|
||||
"version": 237,
|
||||
"versionNonce": 220533858,
|
||||
"isDeleted": false,
|
||||
"id": "ufXZhHDFuihic0jU210X8",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 257.6329680816313,
|
||||
"y": 579.0412908392208,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#1faf98",
|
||||
"width": 481.53809559813783,
|
||||
"height": 481.53809559813783,
|
||||
"seed": 744693632,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"seed": 744693632,
|
||||
"version": 236,
|
||||
"versionNonce": 1099552896,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1651467092353,
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 533,
|
||||
"versionNonce": 146319488,
|
||||
"version": 534,
|
||||
"versionNonce": 313416382,
|
||||
"isDeleted": false,
|
||||
"id": "hPRUDN6SwwxNALCFa6rYB",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -77,7 +77,7 @@
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467106457,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
@@ -91,8 +91,8 @@
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 606,
|
||||
"versionNonce": 1956728704,
|
||||
"version": 608,
|
||||
"versionNonce": 2047359010,
|
||||
"isDeleted": false,
|
||||
"id": "O6LsqUbz9_Git5cLAzGhJ",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -111,7 +111,7 @@
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467142240,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
@@ -125,8 +125,8 @@
|
||||
},
|
||||
{
|
||||
"type": "ellipse",
|
||||
"version": 1001,
|
||||
"versionNonce": 1254697088,
|
||||
"version": 1002,
|
||||
"versionNonce": 869290750,
|
||||
"isDeleted": false,
|
||||
"id": "DUaacDwmSlxMWxQc9k7RX",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -147,14 +147,14 @@
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "ellipse",
|
||||
"version": 914,
|
||||
"versionNonce": 1810304,
|
||||
"version": 920,
|
||||
"versionNonce": 1850794978,
|
||||
"isDeleted": false,
|
||||
"id": "D4JhsJph47k2QoB9fNuJK",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -174,15 +174,24 @@
|
||||
"B0twdI68Hz7VWMi4UlAOW"
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467104973,
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "3e_7qABlY9opKUZCiwA8K",
|
||||
"type": "arrow"
|
||||
},
|
||||
{
|
||||
"id": "qaQmaR2NsIRdwlvvJ4r0x",
|
||||
"type": "arrow"
|
||||
}
|
||||
],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 574,
|
||||
"versionNonce": 1485838464,
|
||||
"version": 575,
|
||||
"versionNonce": 109658942,
|
||||
"isDeleted": false,
|
||||
"id": "o0Agc55hL44xHW-ZToF4P",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -203,7 +212,7 @@
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
@@ -217,8 +226,8 @@
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 920,
|
||||
"versionNonce": 1249619840,
|
||||
"version": 921,
|
||||
"versionNonce": 1947080610,
|
||||
"isDeleted": false,
|
||||
"id": "tYHC-hmS7pDvbvw9mqXFg",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -248,14 +257,14 @@
|
||||
"id": "ar58-5fnU7z_xVgO1qNsi"
|
||||
}
|
||||
],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 915,
|
||||
"versionNonce": 1878591616,
|
||||
"version": 916,
|
||||
"versionNonce": 758786942,
|
||||
"isDeleted": false,
|
||||
"id": "ar58-5fnU7z_xVgO1qNsi",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -276,7 +285,7 @@
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
@@ -290,8 +299,8 @@
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 936,
|
||||
"versionNonce": 1851375488,
|
||||
"version": 937,
|
||||
"versionNonce": 2070860642,
|
||||
"isDeleted": false,
|
||||
"id": "Un4YWq1C54B8PnUiK5agt",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -325,14 +334,14 @@
|
||||
"id": "tRDt4Vip1_Ois0oz3rbzx"
|
||||
}
|
||||
],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 923,
|
||||
"versionNonce": 214169728,
|
||||
"version": 924,
|
||||
"versionNonce": 1445202878,
|
||||
"isDeleted": false,
|
||||
"id": "tRDt4Vip1_Ois0oz3rbzx",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -353,7 +362,7 @@
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
@@ -367,8 +376,8 @@
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 966,
|
||||
"versionNonce": 200658816,
|
||||
"version": 967,
|
||||
"versionNonce": 381818658,
|
||||
"isDeleted": false,
|
||||
"id": "dfPlLg74polPs4cRMjLMH",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -406,14 +415,14 @@
|
||||
"id": "nF3MdAxVTmtMBuLT2YClm"
|
||||
}
|
||||
],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 961,
|
||||
"versionNonce": 850454656,
|
||||
"version": 962,
|
||||
"versionNonce": 1063773182,
|
||||
"isDeleted": false,
|
||||
"id": "nF3MdAxVTmtMBuLT2YClm",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -434,7 +443,7 @@
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
@@ -448,8 +457,8 @@
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 985,
|
||||
"versionNonce": 999284608,
|
||||
"version": 986,
|
||||
"versionNonce": 913760994,
|
||||
"isDeleted": false,
|
||||
"id": "IHNH37dUIbqk92l6XDzjC",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -487,14 +496,14 @@
|
||||
"id": "w0udDoif6KaJf9if4gBJ-"
|
||||
}
|
||||
],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 978,
|
||||
"versionNonce": 1837095040,
|
||||
"version": 979,
|
||||
"versionNonce": 990295102,
|
||||
"isDeleted": false,
|
||||
"id": "w0udDoif6KaJf9if4gBJ-",
|
||||
"fillStyle": "cross-hatch",
|
||||
@@ -515,7 +524,7 @@
|
||||
],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651467104973,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 16,
|
||||
@@ -526,6 +535,314 @@
|
||||
"verticalAlign": "middle",
|
||||
"containerId": "IHNH37dUIbqk92l6XDzjC",
|
||||
"originalText": "<Service>"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 98,
|
||||
"versionNonce": 1696347810,
|
||||
"isDeleted": false,
|
||||
"id": "tnSu5RK3WUVsB4V6xVEB_",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 5.405005496849592,
|
||||
"x": 254.6341399861655,
|
||||
"y": 614.6854873015465,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"width": 85,
|
||||
"height": 25,
|
||||
"seed": 1358336828,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Camudna",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Camudna"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 108,
|
||||
"versionNonce": 853638270,
|
||||
"isDeleted": false,
|
||||
"id": "8PdMc9CKf7_wB9HltATfS",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0.8277877160392517,
|
||||
"x": 669.7888835893037,
|
||||
"y": 617.0664954874768,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"width": 56,
|
||||
"height": 25,
|
||||
"seed": 897340548,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "REST",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "REST"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 197,
|
||||
"versionNonce": 56693346,
|
||||
"isDeleted": false,
|
||||
"id": "O-gcV4Xub96PDmZagZkCt",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0.8525894886685323,
|
||||
"x": 263.5265785916889,
|
||||
"y": 987.6251081157312,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"width": 39,
|
||||
"height": 25,
|
||||
"seed": 2009614340,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Mail",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Mail"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 123,
|
||||
"versionNonce": 750337214,
|
||||
"isDeleted": false,
|
||||
"id": "mlzxOy-jJfWUTS3KVuG0s",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 5.684601839140172,
|
||||
"x": 622.3952730792461,
|
||||
"y": 1023.3642636484051,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"width": 100,
|
||||
"height": 25,
|
||||
"seed": 890003004,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Database",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Database"
|
||||
},
|
||||
{
|
||||
"id": "HPLsoqNTUAa59obKhxgFW",
|
||||
"type": "arrow",
|
||||
"x": 780.8409587500314,
|
||||
"y": 788.8310372713305,
|
||||
"width": 80.50163028766883,
|
||||
"height": 0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"seed": 307211938,
|
||||
"version": 256,
|
||||
"versionNonce": 68449826,
|
||||
"isDeleted": false,
|
||||
"boundElements": null,
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
-80.50163028766883,
|
||||
0
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": null,
|
||||
"endBinding": null,
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow"
|
||||
},
|
||||
{
|
||||
"type": "arrow",
|
||||
"version": 161,
|
||||
"versionNonce": 1311700222,
|
||||
"isDeleted": false,
|
||||
"id": "3e_7qABlY9opKUZCiwA8K",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 683.0494626307682,
|
||||
"y": 788.3321183744032,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"width": 83.20853841275425,
|
||||
"height": 0,
|
||||
"seed": 1626823166,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"startBinding": {
|
||||
"elementId": "D4JhsJph47k2QoB9fNuJK",
|
||||
"focus": 0.252159516599131,
|
||||
"gap": 30.147598375692354
|
||||
},
|
||||
"endBinding": null,
|
||||
"lastCommittedPoint": null,
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
-83.20853841275425,
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "arrow",
|
||||
"version": 550,
|
||||
"versionNonce": 673538530,
|
||||
"isDeleted": false,
|
||||
"id": "ye-E3Pcgp-HdQGwxWDpl2",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 3.141592653589793,
|
||||
"x": 296.1558256475763,
|
||||
"y": 785.2611466470457,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"width": 80.50163028766883,
|
||||
"height": 0,
|
||||
"seed": 1963630014,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"startBinding": null,
|
||||
"endBinding": null,
|
||||
"lastCommittedPoint": null,
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
-80.50163028766883,
|
||||
0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "arrow",
|
||||
"version": 460,
|
||||
"versionNonce": 1623434558,
|
||||
"isDeleted": false,
|
||||
"id": "qaQmaR2NsIRdwlvvJ4r0x",
|
||||
"fillStyle": "cross-hatch",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 3.141592653589793,
|
||||
"x": 398.1846318545008,
|
||||
"y": 784.6753250115426,
|
||||
"strokeColor": "#000",
|
||||
"backgroundColor": "#f39000",
|
||||
"width": 83.20853841275425,
|
||||
"height": 0,
|
||||
"seed": 751150370,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "round",
|
||||
"boundElements": [],
|
||||
"updated": 1651486834502,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"startBinding": {
|
||||
"elementId": "D4JhsJph47k2QoB9fNuJK",
|
||||
"focus": -0.2718056607180316,
|
||||
"gap": 28.308394012919138
|
||||
},
|
||||
"endBinding": null,
|
||||
"lastCommittedPoint": null,
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow",
|
||||
"points": [
|
||||
[
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
-83.20853841275425,
|
||||
0
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"appState": {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 MiB After Width: | Height: | Size: 5.7 MiB |
2
pom.xml
2
pom.xml
@@ -125,7 +125,7 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${artifactId}</finalName>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.common;
|
||||
|
||||
public class ProcessConstants {
|
||||
public static final String PROCESS_DEFINITION = "Loan_Agreement";
|
||||
|
||||
public static final String START_EVENT_MESSAGE_REF = "loanAgreementReceivedMessage";
|
||||
public class LoanAgreement {
|
||||
|
||||
public static final String PROCESS_DEFINITION = "Loan_Agreement";
|
||||
public static final String START_EVENT_MESSAGE_REF = "loanAgreementReceivedMessage";
|
||||
public static final String LOAN_AGREEMENT_NUMBER = "loanAgreementNumber";
|
||||
}
|
||||
|
||||
public static final String LOAN_AGREEMENT_NUMBER = "loanAgreementNumber";
|
||||
}
|
||||
public class CrossSellingRecommendation {
|
||||
|
||||
public static final String PROCESS_DEFINITION = "Cross_Selling_Recommendation";
|
||||
public static final String START_EVENT_MESSAGE_REF = "crossSellingPotentialDiscoveredMessage";
|
||||
public static final String CUSTOMER_NUMBER = "customerNumber";
|
||||
public static final String CONTENT_NUMBER = "contentNumber";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.camunda.bpm.engine.delegate.JavaDelegate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.camunda.bpm.engine.delegate.JavaDelegate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.in.process;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreementNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.usecase.out.LoanAgreementQuery;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.camunda.bpm.engine.RuntimeService;
|
||||
import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.camunda.bpm.engine.delegate.JavaDelegate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CUSTOMER_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.START_EVENT_MESSAGE_REF;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class SendCrossSellingRecommendation implements JavaDelegate {
|
||||
|
||||
private final RuntimeService runtimeService;
|
||||
private final LoanAgreementQuery loanAgreementQuery;
|
||||
|
||||
@Override
|
||||
public void execute(DelegateExecution execution) {
|
||||
Long loanNumber = (Long) execution.getVariable(LOAN_AGREEMENT_NUMBER);
|
||||
LoanAgreement loanAgreement = loanAgreementQuery.loadByNumber(new LoanAgreementNumber(loanNumber));
|
||||
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
processVariables.put(CUSTOMER_NUMBER, loanAgreement.getRecipient().getCustomerNumber().getValue());
|
||||
|
||||
runtimeService.startProcessInstanceByMessage(
|
||||
START_EVENT_MESSAGE_REF,
|
||||
buildCrossSellingBusinessKey(loanNumber, execution.getBusinessKey()),
|
||||
processVariables
|
||||
);
|
||||
}
|
||||
|
||||
private String buildCrossSellingBusinessKey(Long loanNumber, String caseId) {
|
||||
return caseId + "-" + loanNumber;
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.in.web;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.Amount;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.Recipient;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Recipient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("LoanAgreementMapperWeb")
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.out.db;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.*;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.Amount;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreementNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Recipient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("LoanAgreementMapperDb")
|
||||
|
||||
@@ -10,8 +10,8 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.START_EVENT_MESSAGE_REF;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.START_EVENT_MESSAGE_REF;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Recipient;
|
||||
import io.github.domainprimitives.object.Aggregate;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model;
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import io.github.domainprimitives.object.ComposedValueObject;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.in.process;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.in.RecommendationPicker;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.camunda.bpm.engine.delegate.JavaDelegate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CONTENT_NUMBER;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class PickContent implements JavaDelegate {
|
||||
|
||||
private final RecommendationPicker recommendationPicker;
|
||||
|
||||
@Override
|
||||
public void execute(DelegateExecution execution) {
|
||||
ContentId contentId = recommendationPicker.pickContent();
|
||||
execution.setVariable(CONTENT_NUMBER, contentId.getValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.in.process;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Recommendation;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Customer;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.RecommendationQuery;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.SendNotification;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.camunda.bpm.engine.delegate.JavaDelegate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CONTENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CUSTOMER_NUMBER;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class SendRecommendation implements JavaDelegate {
|
||||
|
||||
private final SendNotification sendNotification;
|
||||
private final RecommendationQuery recommendationQuery;
|
||||
|
||||
@Override
|
||||
public void execute(DelegateExecution execution) {
|
||||
Long contentId = (Long) execution.getVariable(CONTENT_NUMBER);
|
||||
String customerId = (String) execution.getVariable(CUSTOMER_NUMBER);
|
||||
Content content = recommendationQuery.findContentById(new ContentId(contentId));
|
||||
Customer customer = recommendationQuery.findCustomerById(new CustomerNumber(customerId));
|
||||
|
||||
Recommendation recommendation = new Recommendation(customer, content);
|
||||
|
||||
sendNotification.send(recommendation);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.console;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Recommendation;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.SendNotification;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SendNotificationClient implements SendNotification {
|
||||
@Override
|
||||
public void send(Recommendation recommendation) {
|
||||
log.info("Sending recommendation '{}' to customer {}",
|
||||
recommendation.getContent().getDescription().getValue(), recommendation.getCustomer().getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content.ContentCRUDRepository;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content.ContentMapper;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content.ContentNotFoundException;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Customer;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.RecommendationQuery;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class RecommendationRepository implements RecommendationQuery {
|
||||
|
||||
private final ContentCRUDRepository contentCRUDRepository;
|
||||
private final ContentMapper mapper;
|
||||
|
||||
@Override
|
||||
public Content findContentById(ContentId contentId) {
|
||||
return contentCRUDRepository.findById(contentId.getValue())
|
||||
.map(mapper::mapToDomain)
|
||||
.orElseThrow(() -> new ContentNotFoundException(
|
||||
format("Could not find recommendation content with id %s", contentId.getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Customer findCustomerById(CustomerNumber customerNumber) {
|
||||
// Here would be a own CRUDRepository for the customer information we need during recommendation
|
||||
return new Customer(
|
||||
customerNumber,
|
||||
new Name("Max Mustermann"),
|
||||
new MailAddress("max@mustermann.de")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ContentCRUDRepository extends CrudRepository<ContentEntity, Long> {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import static javax.persistence.GenerationType.AUTO;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
public class ContentEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy= AUTO)
|
||||
private Long id;
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Description;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ContentMapper {
|
||||
|
||||
public Content mapToDomain(ContentEntity contentEntity) {
|
||||
return new Content(
|
||||
new ContentId(contentEntity.getId()),
|
||||
new Description(contentEntity.getContent())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content;
|
||||
|
||||
public class ContentNotFoundException extends RuntimeException {
|
||||
public ContentNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class ExampleContentRunner implements CommandLineRunner {
|
||||
|
||||
private final ContentCRUDRepository contentCRUDRepository;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
ContentEntity contentEntity = new ContentEntity();
|
||||
contentEntity.setId(1L);
|
||||
contentEntity.setContent("Here we do some cross-selling");
|
||||
contentCRUDRepository.save(contentEntity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model;
|
||||
|
||||
import io.github.domainprimitives.object.Entity;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Content extends Entity {
|
||||
|
||||
private final ContentId contentId;
|
||||
private final Description description;
|
||||
|
||||
public Content(ContentId contentId, Description description) {
|
||||
this.contentId = contentId;
|
||||
this.description = description;
|
||||
validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validate() {
|
||||
validateNotNull(contentId, "ContentId");
|
||||
validateNotNull(description, "Description");
|
||||
evaluateValidations();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model;
|
||||
|
||||
import io.github.domainprimitives.type.ValueObject;
|
||||
|
||||
import static io.github.domainprimitives.validation.Constraints.isNotNullLong;
|
||||
|
||||
public class ContentId extends ValueObject<Long> {
|
||||
public ContentId(Long value) {
|
||||
super(value, isNotNullLong());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model;
|
||||
|
||||
import io.github.domainprimitives.type.ValueObject;
|
||||
|
||||
import static io.github.domainprimitives.validation.Constraints.isNotBlank;
|
||||
|
||||
public class Description extends ValueObject<String> {
|
||||
public Description(String value) {
|
||||
super(value, isNotBlank());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Customer;
|
||||
import io.github.domainprimitives.object.Aggregate;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Recommendation extends Aggregate {
|
||||
|
||||
private final Customer customer;
|
||||
private final Content content;
|
||||
|
||||
public Recommendation(Customer customer, Content content) {
|
||||
this.customer = customer;
|
||||
this.content = content;
|
||||
this.validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validate() {
|
||||
validateNotNull(customer, "Customer");
|
||||
validateNotNull(content, "Content");
|
||||
evaluateValidations();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import io.github.domainprimitives.object.ComposedValueObject;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Customer extends ComposedValueObject {
|
||||
|
||||
private final CustomerNumber customerNumber;
|
||||
private final Name name;
|
||||
private final MailAddress mailAddress;
|
||||
|
||||
public Customer(CustomerNumber customerNumber, Name name, MailAddress mailAddress) {
|
||||
this.customerNumber = customerNumber;
|
||||
this.name = name;
|
||||
this.mailAddress = mailAddress;
|
||||
this.validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validate() {
|
||||
validateNotNull(customerNumber, "Customer Number");
|
||||
validateNotNull(name, "Name");
|
||||
validateNotNull(mailAddress, "Mail Address");
|
||||
evaluateValidations();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer;
|
||||
|
||||
import io.github.domainprimitives.type.ValueObject;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static io.github.domainprimitives.validation.Constraints.isPattern;
|
||||
|
||||
public class MailAddress extends ValueObject<String> {
|
||||
|
||||
public static final String VALID_EMAIL_ADDRESS_REGEX =
|
||||
Pattern.compile("^[a-zA-Z0-9_!#$%&’*+=?`{|}~^.-]+@[a-zA-Z0-9.-]+$",
|
||||
Pattern.CASE_INSENSITIVE).pattern();
|
||||
|
||||
|
||||
public MailAddress(String value) {
|
||||
super(value, isPattern(VALID_EMAIL_ADDRESS_REGEX));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer;
|
||||
|
||||
import io.github.domainprimitives.type.ValueObject;
|
||||
|
||||
import static io.github.domainprimitives.validation.Constraints.hasMinLength;
|
||||
|
||||
public class Name extends ValueObject<String> {
|
||||
public Name(String value) {
|
||||
super(value, hasMinLength(3));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.service;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.in.RecommendationPicker;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.RecommendationQuery;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
class RecommendationService implements RecommendationPicker {
|
||||
|
||||
private final RecommendationQuery recommendationQuery;
|
||||
|
||||
@Override
|
||||
public ContentId pickContent() {
|
||||
// Magically decide which content is the right one for the customer
|
||||
return recommendationQuery.findContentById(new ContentId(1L)).getContentId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.usecase.in;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
|
||||
public interface RecommendationPicker {
|
||||
ContentId pickContent();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Customer;
|
||||
|
||||
public interface RecommendationQuery {
|
||||
Content findContentById(ContentId contentId);
|
||||
Customer findCustomerById(CustomerNumber customerNumber);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Recommendation;
|
||||
|
||||
public interface SendNotification {
|
||||
void send(Recommendation recommendation);
|
||||
}
|
||||
67
src/main/resources/cross_selling_recommendation.bpmn
Normal file
67
src/main/resources/cross_selling_recommendation.bpmn
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_02tppq7" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.17.0">
|
||||
<bpmn:collaboration id="Collaboration_197td5k">
|
||||
<bpmn:participant id="Participant_1y5ozpf" name="Recommendation example" processRef="Cross_Selling_Recommendation" />
|
||||
</bpmn:collaboration>
|
||||
<bpmn:process id="Cross_Selling_Recommendation" name="Cross Selling Recommendation" isExecutable="true">
|
||||
<bpmn:serviceTask id="PickContentServiceTask" name="Pick Content" camunda:delegateExpression="${pickContent}">
|
||||
<bpmn:incoming>Flow_14xjzhy</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0klv1t5</bpmn:outgoing>
|
||||
</bpmn:serviceTask>
|
||||
<bpmn:startEvent id="CrossSellingStartEvent" name="Cross-Selling potential discovered">
|
||||
<bpmn:outgoing>Flow_14xjzhy</bpmn:outgoing>
|
||||
<bpmn:messageEventDefinition id="MessageEventDefinition_1ibjd8g" messageRef="Message_0hftsl2" />
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_14xjzhy" sourceRef="CrossSellingStartEvent" targetRef="PickContentServiceTask" />
|
||||
<bpmn:endEvent id="CrossSellingRecommendationEndEvent" name="Cross-Selling recommendation sent">
|
||||
<bpmn:incoming>Flow_1bnyw18</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0klv1t5" sourceRef="PickContentServiceTask" targetRef="SendRecommendationServiceTask" />
|
||||
<bpmn:sequenceFlow id="Flow_1bnyw18" sourceRef="SendRecommendationServiceTask" targetRef="CrossSellingRecommendationEndEvent" />
|
||||
<bpmn:serviceTask id="SendRecommendationServiceTask" name="Send Recommendation" camunda:delegateExpression="${sendRecommendation}">
|
||||
<bpmn:incoming>Flow_0klv1t5</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1bnyw18</bpmn:outgoing>
|
||||
</bpmn:serviceTask>
|
||||
</bpmn:process>
|
||||
<bpmn:message id="Message_0hftsl2" name="crossSellingPotentialDiscoveredMessage" />
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_197td5k">
|
||||
<bpmndi:BPMNShape id="Participant_1y5ozpf_di" bpmnElement="Participant_1y5ozpf" isHorizontal="true">
|
||||
<dc:Bounds x="160" y="80" width="610" height="210" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_14xjzhy_di" bpmnElement="Flow_14xjzhy">
|
||||
<di:waypoint x="288" y="160" />
|
||||
<di:waypoint x="340" y="160" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0klv1t5_di" bpmnElement="Flow_0klv1t5">
|
||||
<di:waypoint x="440" y="160" />
|
||||
<di:waypoint x="500" y="160" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1bnyw18_di" bpmnElement="Flow_1bnyw18">
|
||||
<di:waypoint x="600" y="160" />
|
||||
<di:waypoint x="662" y="160" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Activity_0bsm7s4_di" bpmnElement="PickContentServiceTask">
|
||||
<dc:Bounds x="340" y="120" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1ct00fd_di" bpmnElement="CrossSellingStartEvent">
|
||||
<dc:Bounds x="252" y="142" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="237" y="185" width="66" height="40" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_18vk8pm_di" bpmnElement="CrossSellingRecommendationEndEvent">
|
||||
<dc:Bounds x="662" y="142" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="640" y="185" width="82" height="40" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="BPMNShape_1shn36r" bpmnElement="SendRecommendationServiceTask">
|
||||
<dc:Bounds x="500" y="120" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
@@ -18,26 +18,15 @@
|
||||
<bpmn:outgoing>Flow_0xpo6jp</bpmn:outgoing>
|
||||
<bpmn:outgoing>Flow_1hri7xc</bpmn:outgoing>
|
||||
</bpmn:exclusiveGateway>
|
||||
<bpmn:endEvent id="LoanAgreementNotApprovedEndEvent" name="loan agreement not approved">
|
||||
<bpmn:incoming>Flow_0eif63m</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:endEvent id="LoanAgreementApprovedEndEvent" name="loan agreement approved">
|
||||
<bpmn:incoming>Flow_1uqmps7</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:serviceTask id="ApproveLoanAgreementServiceTask" name="Approve loan agreement" camunda:delegateExpression="${approveLoanAgreement}">
|
||||
<bpmn:incoming>Flow_1hri7xc</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1uqmps7</bpmn:outgoing>
|
||||
</bpmn:serviceTask>
|
||||
<bpmn:serviceTask id="RejectLoanAgreementServiceTask" name="Rejection loan agreement" camunda:delegateExpression="${rejectionLoanAgreement}">
|
||||
<bpmn:incoming>Flow_0xpo6jp</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0eif63m</bpmn:outgoing>
|
||||
</bpmn:serviceTask>
|
||||
<bpmn:startEvent id="LoanAgreementReciedStartEvent" name="loan agreement recived" camunda:asyncAfter="true">
|
||||
<bpmn:outgoing>Flow_1rrsueh</bpmn:outgoing>
|
||||
<bpmn:messageEventDefinition id="MessageEventDefinition_1j9r08u" messageRef="Message_0o102df" />
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0eif63m" sourceRef="RejectLoanAgreementServiceTask" targetRef="LoanAgreementNotApprovedEndEvent" />
|
||||
<bpmn:sequenceFlow id="Flow_1uqmps7" sourceRef="ApproveLoanAgreementServiceTask" targetRef="LoanAgreementApprovedEndEvent" />
|
||||
<bpmn:sequenceFlow id="Flow_1uqmps7" sourceRef="ApproveLoanAgreementServiceTask" targetRef="SendCrossSellingEvent" />
|
||||
<bpmn:sequenceFlow id="Flow_1hri7xc" name="yes" sourceRef="IsApprovedGateway" targetRef="ApproveLoanAgreementServiceTask">
|
||||
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${approved}</bpmn:conditionExpression>
|
||||
</bpmn:sequenceFlow>
|
||||
@@ -46,28 +35,38 @@
|
||||
</bpmn:sequenceFlow>
|
||||
<bpmn:sequenceFlow id="Flow_00ukhfv" sourceRef="ApproveAgreementRuleTask" targetRef="IsApprovedGateway" />
|
||||
<bpmn:sequenceFlow id="Flow_1rrsueh" sourceRef="LoanAgreementReciedStartEvent" targetRef="ApproveAgreementRuleTask" />
|
||||
<bpmn:serviceTask id="RejectLoanAgreementServiceTask" name="Rejection loan agreement" camunda:delegateExpression="${rejectionLoanAgreement}">
|
||||
<bpmn:incoming>Flow_0xpo6jp</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0eif63m</bpmn:outgoing>
|
||||
</bpmn:serviceTask>
|
||||
<bpmn:sequenceFlow id="Flow_0eif63m" sourceRef="RejectLoanAgreementServiceTask" targetRef="LoanAgreementNotApprovedEndEvent" />
|
||||
<bpmn:endEvent id="LoanAgreementApprovedEndEvent" name="loan agreement approved">
|
||||
<bpmn:incoming>Flow_1pvaqlv</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1pvaqlv" sourceRef="SendCrossSellingEvent" targetRef="LoanAgreementApprovedEndEvent" />
|
||||
<bpmn:intermediateThrowEvent id="SendCrossSellingEvent" name="Send cross-selling recommendaiton">
|
||||
<bpmn:incoming>Flow_1uqmps7</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1pvaqlv</bpmn:outgoing>
|
||||
<bpmn:messageEventDefinition id="MessageEventDefinition_0drw25h" camunda:delegateExpression="${sendCrossSellingRecommendation}" />
|
||||
</bpmn:intermediateThrowEvent>
|
||||
<bpmn:endEvent id="LoanAgreementNotApprovedEndEvent" name="loan agreement not approved">
|
||||
<bpmn:incoming>Flow_0eif63m</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
</bpmn:process>
|
||||
<bpmn:message id="Message_0o102df" name="loanAgreementReceivedMessage" />
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_0w4ikjr">
|
||||
<bpmndi:BPMNShape id="Participant_1p6ilgg_di" bpmnElement="Participant_1p6ilgg" isHorizontal="true">
|
||||
<dc:Bounds x="160" y="177" width="720" height="250" />
|
||||
<dc:Bounds x="160" y="177" width="820" height="255" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_0eif63m_di" bpmnElement="Flow_0eif63m">
|
||||
<di:waypoint x="700" y="360" />
|
||||
<di:waypoint x="772" y="360" />
|
||||
<bpmndi:BPMNEdge id="Flow_1rrsueh_di" bpmnElement="Flow_1rrsueh">
|
||||
<di:waypoint x="258" y="237" />
|
||||
<di:waypoint x="330" y="237" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1uqmps7_di" bpmnElement="Flow_1uqmps7">
|
||||
<di:waypoint x="700" y="237" />
|
||||
<di:waypoint x="772" y="237" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1hri7xc_di" bpmnElement="Flow_1hri7xc">
|
||||
<di:waypoint x="535" y="237" />
|
||||
<di:waypoint x="600" y="237" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="559" y="219" width="18" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
<bpmndi:BPMNEdge id="Flow_00ukhfv_di" bpmnElement="Flow_00ukhfv">
|
||||
<di:waypoint x="430" y="237" />
|
||||
<di:waypoint x="485" y="237" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0xpo6jp_di" bpmnElement="Flow_0xpo6jp">
|
||||
<di:waypoint x="510" y="262" />
|
||||
@@ -77,13 +76,24 @@
|
||||
<dc:Bounds x="519" y="308" width="13" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_00ukhfv_di" bpmnElement="Flow_00ukhfv">
|
||||
<di:waypoint x="430" y="237" />
|
||||
<di:waypoint x="485" y="237" />
|
||||
<bpmndi:BPMNEdge id="Flow_1hri7xc_di" bpmnElement="Flow_1hri7xc">
|
||||
<di:waypoint x="535" y="237" />
|
||||
<di:waypoint x="600" y="237" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="559" y="219" width="18" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1rrsueh_di" bpmnElement="Flow_1rrsueh">
|
||||
<di:waypoint x="258" y="237" />
|
||||
<di:waypoint x="330" y="237" />
|
||||
<bpmndi:BPMNEdge id="Flow_1uqmps7_di" bpmnElement="Flow_1uqmps7">
|
||||
<di:waypoint x="700" y="237" />
|
||||
<di:waypoint x="772" y="237" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0eif63m_di" bpmnElement="Flow_0eif63m">
|
||||
<di:waypoint x="700" y="360" />
|
||||
<di:waypoint x="772" y="360" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1pvaqlv_di" bpmnElement="Flow_1pvaqlv">
|
||||
<di:waypoint x="808" y="237" />
|
||||
<di:waypoint x="882" y="237" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="Activity_1244zx8_di" bpmnElement="ApproveAgreementRuleTask">
|
||||
<dc:Bounds x="330" y="197" width="100" height="80" />
|
||||
@@ -95,18 +105,6 @@
|
||||
<dc:Bounds x="478" y="182" width="65" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_0r30zqn_di" bpmnElement="LoanAgreementNotApprovedEndEvent">
|
||||
<dc:Bounds x="772" y="342" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="752" y="385" width="77" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1csw1p9_di" bpmnElement="LoanAgreementApprovedEndEvent">
|
||||
<dc:Bounds x="772" y="219" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="752" y="262" width="77" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_13yt0mp_di" bpmnElement="ApproveLoanAgreementServiceTask">
|
||||
<dc:Bounds x="600" y="197" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
@@ -121,22 +119,40 @@
|
||||
<dc:Bounds x="202" y="262" width="77" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="BPMNShape_1ilsqo5" bpmnElement="Participant_0z5fkq5" isHorizontal="true">
|
||||
<dc:Bounds x="500" y="80" width="300" height="60" />
|
||||
<bpmndi:BPMNLabel />
|
||||
<bpmndi:BPMNShape id="Event_0mxjaa5_di" bpmnElement="LoanAgreementApprovedEndEvent">
|
||||
<dc:Bounds x="882" y="219" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="862" y="262" width="77" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1hg5yw3_di" bpmnElement="SendCrossSellingEvent">
|
||||
<dc:Bounds x="772" y="219" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="750" y="262" width="82" height="40" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1i3yo9j_di" bpmnElement="LoanAgreementNotApprovedEndEvent">
|
||||
<dc:Bounds x="772" y="342" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="752" y="385" width="77" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_1s9mw1a_di" bpmnElement="Participant_0y932pu" isHorizontal="true">
|
||||
<dc:Bounds x="500" y="460" width="300" height="60" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1ax0a41_di" bpmnElement="Flow_1ax0a41">
|
||||
<di:waypoint x="650" y="197" />
|
||||
<di:waypoint x="650" y="140" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="BPMNShape_1ilsqo5" bpmnElement="Participant_0z5fkq5" isHorizontal="true">
|
||||
<dc:Bounds x="500" y="80" width="300" height="60" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1ytdopc_di" bpmnElement="Flow_1ytdopc">
|
||||
<di:waypoint x="650" y="400" />
|
||||
<di:waypoint x="650" y="460" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1ax0a41_di" bpmnElement="Flow_1ax0a41">
|
||||
<di:waypoint x="650" y="197" />
|
||||
<di:waypoint x="650" y="140" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package de.weinbrecht.luc.bpm.architecture;
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.in.process.ApproveLoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.in.process.RejectionLoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.in.process.SendCrossSellingRecommendation;
|
||||
import org.camunda.bpm.dmn.engine.DmnDecisionTableResult;
|
||||
import org.camunda.bpm.engine.runtime.ProcessInstance;
|
||||
import org.camunda.bpm.engine.test.Deployment;
|
||||
@@ -16,8 +17,8 @@ import org.junit.jupiter.params.provider.MethodSource;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.PROCESS_DEFINITION;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.PROCESS_DEFINITION;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.assertThat;
|
||||
@@ -35,7 +36,11 @@ class ProcessTest {
|
||||
private static final String START_EVENT = "LoanAgreementReciedStartEvent";
|
||||
private static final String APPROVE_RULE_TASK = "ApproveAgreementRuleTask";
|
||||
private static final String APPROVE_AGREEMENT_SERVICE_TASK = "ApproveLoanAgreementServiceTask";
|
||||
private static final String SEND_CROSS_SELLING_EVENT = "SendCrossSellingEvent";
|
||||
private static final String APPROVED_END_EVENT = "LoanAgreementApprovedEndEvent";
|
||||
|
||||
private static final String REJECT_AGREEMENT_SERVICE_TASK = "RejectLoanAgreementServiceTask";
|
||||
private static final String NOT_APPROVED_END_EVENT = "LoanAgreementNotApprovedEndEvent";
|
||||
|
||||
private static final String DMN_DEFINITION = "approvement-check";
|
||||
|
||||
@@ -43,6 +48,7 @@ class ProcessTest {
|
||||
void setUp() {
|
||||
registerJavaDelegateMock(ApproveLoanAgreement.class);
|
||||
registerJavaDelegateMock(RejectionLoanAgreement.class);
|
||||
registerJavaDelegateMock(SendCrossSellingRecommendation.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -61,8 +67,11 @@ class ProcessTest {
|
||||
assertThat(processInstance)
|
||||
.hasPassed(START_EVENT,
|
||||
APPROVE_RULE_TASK,
|
||||
APPROVE_AGREEMENT_SERVICE_TASK);
|
||||
APPROVE_AGREEMENT_SERVICE_TASK,
|
||||
SEND_CROSS_SELLING_EVENT,
|
||||
APPROVED_END_EVENT);
|
||||
|
||||
verifyJavaDelegateMock(SendCrossSellingRecommendation.class).executed();
|
||||
verifyJavaDelegateMock(ApproveLoanAgreement.class).executed();
|
||||
|
||||
assertThat(processInstance).isEnded();
|
||||
@@ -84,7 +93,8 @@ class ProcessTest {
|
||||
assertThat(processInstance)
|
||||
.hasPassed(START_EVENT,
|
||||
APPROVE_RULE_TASK,
|
||||
REJECT_AGREEMENT_SERVICE_TASK);
|
||||
REJECT_AGREEMENT_SERVICE_TASK,
|
||||
NOT_APPROVED_END_EVENT);
|
||||
|
||||
verifyJavaDelegateMock(RejectionLoanAgreement.class).executed();
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@MockitoSettings
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@MockitoSettings
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.in.process;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.usecase.out.LoanAgreementQuery;
|
||||
import org.camunda.bpm.engine.RuntimeService;
|
||||
import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CUSTOMER_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.START_EVENT_MESSAGE_REF;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.TestdataGenerator.createLoanAgreementWithNumber;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@MockitoSettings
|
||||
class SendCrossSellingRecommendationTest {
|
||||
|
||||
@InjectMocks
|
||||
private SendCrossSellingRecommendation classUnderTest;
|
||||
|
||||
@Mock
|
||||
private RuntimeService runtimeService;
|
||||
|
||||
@Mock
|
||||
LoanAgreementQuery loanAgreementQuery;
|
||||
|
||||
@Test
|
||||
void should_load_data_and_start_process_by_message() {
|
||||
LoanAgreement loanAgreement = createLoanAgreementWithNumber();
|
||||
String caseId = "11";
|
||||
DelegateExecution delegateExecution = mock(DelegateExecution.class);
|
||||
when(delegateExecution.getBusinessKey()).thenReturn(caseId);
|
||||
when(delegateExecution.getVariable(LOAN_AGREEMENT_NUMBER))
|
||||
.thenReturn(loanAgreement.getLoanAgreementNumber().getValue());
|
||||
when(loanAgreementQuery.loadByNumber(loanAgreement.getLoanAgreementNumber())).thenReturn(loanAgreement);
|
||||
|
||||
classUnderTest.execute(delegateExecution);
|
||||
|
||||
Map<String, Object> processVariables = new HashMap<>();
|
||||
processVariables.put(CUSTOMER_NUMBER, loanAgreement.getRecipient().getCustomerNumber().getValue());
|
||||
verify(runtimeService).startProcessInstanceByMessage(
|
||||
START_EVENT_MESSAGE_REF,
|
||||
caseId + "-" + loanAgreement.getLoanAgreementNumber().getValue(),
|
||||
processVariables
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.adapter.in.web;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.*;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.Amount;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CaseId;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Recipient;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.usecase.in.LoanAgreementCreation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -11,8 +11,8 @@ import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.START_EVENT_MESSAGE_REF;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.LOAN_AGREEMENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.LoanAgreement.START_EVENT_MESSAGE_REF;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@MockitoSettings
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Recipient;
|
||||
import io.github.domainprimitives.validation.InvariantException;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Recipient;
|
||||
import io.github.domainprimitives.validation.InvariantException;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.recipient.Recipient;
|
||||
|
||||
public class TestdataGenerator {
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement;
|
||||
package de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.service;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CaseId;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreement;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.LoanAgreementNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.service.LoanAgreementException;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.service.LoanAgreementService;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.usecase.out.LoanAgreementCommand;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.usecase.out.LoanAgreementDistributor;
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.usecase.out.LoanAgreementQuery;
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.in.process.PickContent;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.in.process.SendRecommendation;
|
||||
import org.camunda.bpm.engine.runtime.ProcessInstance;
|
||||
import org.camunda.bpm.engine.test.Deployment;
|
||||
import org.camunda.bpm.extension.junit5.test.ProcessEngineExtension;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.PROCESS_DEFINITION;
|
||||
import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.assertThat;
|
||||
import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.runtimeService;
|
||||
import static org.camunda.community.mockito.DelegateExpressions.registerJavaDelegateMock;
|
||||
import static org.camunda.community.mockito.DelegateExpressions.verifyJavaDelegateMock;
|
||||
|
||||
@ExtendWith(ProcessEngineExtension.class)
|
||||
class ProcessTest {
|
||||
|
||||
private static final String START_EVENT = "CrossSellingStartEvent";
|
||||
private static final String PICK_CONTENT_SERVICE_TASK = "PickContentServiceTask";
|
||||
private static final String SEND_RECOMMENDATION_SERVICE_TASK = "SendRecommendationServiceTask";
|
||||
private static final String END_EVENT = "CrossSellingRecommendationEndEvent";
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
registerJavaDelegateMock(PickContent.class);
|
||||
registerJavaDelegateMock(SendRecommendation.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deployment(resources = "cross_selling_recommendation.bpmn")
|
||||
void shouldExecuteProcess_happy_path() {
|
||||
ProcessInstance processInstance = runtimeService().startProcessInstanceByKey(
|
||||
PROCESS_DEFINITION
|
||||
);
|
||||
|
||||
assertThat(processInstance)
|
||||
.hasPassedInOrder(
|
||||
START_EVENT,
|
||||
PICK_CONTENT_SERVICE_TASK,
|
||||
SEND_RECOMMENDATION_SERVICE_TASK,
|
||||
END_EVENT);
|
||||
|
||||
verifyJavaDelegateMock(PickContent.class).executed();
|
||||
verifyJavaDelegateMock(SendRecommendation.class).executed();
|
||||
|
||||
assertThat(processInstance).isEnded();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.in.process;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.in.RecommendationPicker;
|
||||
import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CONTENT_NUMBER;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@MockitoSettings
|
||||
class PickContentTest {
|
||||
|
||||
@InjectMocks
|
||||
private PickContent classUnderTest;
|
||||
|
||||
@Mock
|
||||
private RecommendationPicker recommendationPicker;
|
||||
|
||||
@Test
|
||||
void should_call_service_and_set_variable() {
|
||||
ContentId contentId = new ContentId(1L);
|
||||
when(recommendationPicker.pickContent()).thenReturn(contentId);
|
||||
DelegateExecution delegateExecution = mock(DelegateExecution.class);
|
||||
|
||||
classUnderTest.execute(delegateExecution);
|
||||
|
||||
verify(delegateExecution).setVariable(CONTENT_NUMBER, contentId.getValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.in.process;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Description;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Recommendation;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Customer;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Name;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.RecommendationQuery;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.SendNotification;
|
||||
import org.camunda.bpm.engine.delegate.DelegateExecution;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CONTENT_NUMBER;
|
||||
import static de.weinbrecht.luc.bpm.architecture.common.ProcessConstants.CrossSellingRecommendation.CUSTOMER_NUMBER;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@MockitoSettings
|
||||
class SendRecommendationTest {
|
||||
|
||||
@InjectMocks
|
||||
private SendRecommendation classUnderTest;
|
||||
|
||||
@Mock
|
||||
private SendNotification sendNotification;
|
||||
|
||||
@Mock
|
||||
RecommendationQuery recommendationQuery;
|
||||
|
||||
@Test
|
||||
void should_load_data_and_call_service_to_send_notification() {
|
||||
ContentId contentId = new ContentId(1L);
|
||||
CustomerNumber customerNumber = new CustomerNumber("A1");
|
||||
DelegateExecution delegateExecution = mock(DelegateExecution.class);
|
||||
when(delegateExecution.getVariable(CONTENT_NUMBER)).thenReturn(contentId.getValue());
|
||||
when(delegateExecution.getVariable(CUSTOMER_NUMBER)).thenReturn(customerNumber.getValue());
|
||||
Content content = new Content(contentId, new Description("Foo"));
|
||||
when(recommendationQuery.findContentById(contentId)).thenReturn(content);
|
||||
Customer customer = createCustomer(customerNumber);
|
||||
when(recommendationQuery.findCustomerById(customerNumber)).thenReturn(customer);
|
||||
|
||||
classUnderTest.execute(delegateExecution);
|
||||
|
||||
verify(sendNotification).send(new Recommendation(customer, content));
|
||||
}
|
||||
|
||||
private Customer createCustomer(CustomerNumber customerNumber) {
|
||||
return new Customer(
|
||||
customerNumber,
|
||||
new Name("Tester"),
|
||||
new MailAddress("tester@ewb.io")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content.ContentCRUDRepository;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content.ContentEntity;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content.ContentMapper;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content.ContentNotFoundException;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Description;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Customer;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Name;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Answers.CALLS_REAL_METHODS;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@MockitoSettings
|
||||
class RecommendationRepositoryTest {
|
||||
|
||||
@InjectMocks
|
||||
private RecommendationRepository classUnderTest;
|
||||
|
||||
@Mock
|
||||
private ContentCRUDRepository contentCRUDRepository;
|
||||
|
||||
@Mock(answer = CALLS_REAL_METHODS)
|
||||
private ContentMapper contentMapper;
|
||||
|
||||
@Test
|
||||
void should_find_content() {
|
||||
Content content = new Content(new ContentId(1L), new Description("Test"));
|
||||
ContentEntity contentEntity = new ContentEntity();
|
||||
contentEntity.setId(content.getContentId().getValue());
|
||||
contentEntity.setContent(content.getDescription().getValue());
|
||||
when(contentCRUDRepository.findById(content.getContentId().getValue())).thenReturn(of(contentEntity));
|
||||
|
||||
Content result = classUnderTest.findContentById(content.getContentId());
|
||||
|
||||
assertThat(result).isEqualTo(content);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_find_content_throw_custom_exception() {
|
||||
ContentId contentId = new ContentId(1L);
|
||||
when(contentCRUDRepository.findById(contentId.getValue())).thenReturn(empty());
|
||||
|
||||
assertThrows(ContentNotFoundException.class,
|
||||
() -> classUnderTest.findContentById(contentId));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_find_customer() {
|
||||
Customer customer = new Customer(
|
||||
new CustomerNumber("A-11"),
|
||||
new Name("Max Mustermann"),
|
||||
new MailAddress("max@mustermann.de")
|
||||
);
|
||||
|
||||
Customer result = classUnderTest.findCustomerById(customer.getCustomerNumber());
|
||||
|
||||
assertThat(result).isEqualTo(customer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DataJpaTest
|
||||
@Import(ExampleContentRunner.class)
|
||||
class ContentCRUDRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private ContentCRUDRepository contentCRUDRepository;
|
||||
|
||||
@Test
|
||||
void should_find_content() {
|
||||
assertThat(contentCRUDRepository.findById(1L)).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.adapter.out.db.content;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Description;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ContentMapperTest {
|
||||
|
||||
private ContentMapper classUnderTest = new ContentMapper();
|
||||
|
||||
@Test
|
||||
void should_map_all_fields() {
|
||||
Content content = new Content(new ContentId(1L), new Description("Test"));
|
||||
ContentEntity contentEntity = new ContentEntity();
|
||||
contentEntity.setId(content.getContentId().getValue());
|
||||
contentEntity.setContent(content.getDescription().getValue());
|
||||
|
||||
Content result = classUnderTest.mapToDomain(contentEntity);
|
||||
|
||||
assertThat(result).isEqualTo(content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model;
|
||||
|
||||
import io.github.domainprimitives.validation.InvariantException;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class ContentTest {
|
||||
@Test
|
||||
void should_create_valid_object() {
|
||||
ContentId contentId = new ContentId(1L);
|
||||
Description description = new Description("Testing");
|
||||
|
||||
Content content = new Content(contentId, description);
|
||||
|
||||
assertThat(content).isNotNull();
|
||||
assertThat(content.getContentId()).isEqualTo(contentId);
|
||||
assertThat(content.getDescription()).isEqualTo(description);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class InvariantTest {
|
||||
@Test
|
||||
void should_throw_invariant_exception_if_id_is_null() {
|
||||
Description description = new Description("Testing");
|
||||
|
||||
assertThrows(InvariantException.class, () -> new Content(null, description));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_invariant_exception_if_description_is_null() {
|
||||
ContentId contentId = new ContentId(1L);
|
||||
|
||||
assertThrows(InvariantException.class, () -> new Content(contentId, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Customer;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.MailAddress;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer.Name;
|
||||
import io.github.domainprimitives.validation.InvariantException;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class RecommendationTest {
|
||||
@Test
|
||||
void should_create_valid_object() {
|
||||
Content content = new Content(new ContentId(1L), new Description("Test"));
|
||||
Customer customer = new Customer(new CustomerNumber("A"), new Name("Tester"), new MailAddress("tester@web.io"));
|
||||
|
||||
Recommendation recommendation = new Recommendation(customer, content);
|
||||
|
||||
assertThat(recommendation).isNotNull();
|
||||
assertThat(recommendation.getContent()).isEqualTo(content);
|
||||
assertThat(recommendation.getCustomer()).isEqualTo(customer);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class InvariantTest {
|
||||
@Test
|
||||
void should_throw_invariant_exception_if_customer_is_null() {
|
||||
Content content = new Content(new ContentId(1L), new Description("Test"));
|
||||
|
||||
assertThrows(InvariantException.class, () -> new Recommendation(null, content));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_invariant_exception_if_content_is_null() {
|
||||
Customer customer = new Customer(new CustomerNumber("A"), new Name("Tester"), new MailAddress("tester@web.io"));
|
||||
|
||||
assertThrows(InvariantException.class, () -> new Recommendation(customer, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.customer;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.loan.agreement.domain.model.CustomerNumber;
|
||||
import io.github.domainprimitives.validation.InvariantException;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class CustomerTest {
|
||||
@Test
|
||||
void should_create_valid_object() {
|
||||
Name name = new Name("Tester");
|
||||
MailAddress mailAddress = new MailAddress("tester@web.io");
|
||||
CustomerNumber customerNumber = new CustomerNumber("A-1");
|
||||
|
||||
Customer customer = new Customer(customerNumber, name, mailAddress);
|
||||
|
||||
assertThat(customer).isNotNull();
|
||||
assertThat(customer.getCustomerNumber()).isEqualTo(customerNumber);
|
||||
assertThat(customer.getName()).isEqualTo(name);
|
||||
assertThat(customer.getMailAddress()).isEqualTo(mailAddress);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class InvariantTest {
|
||||
@Test
|
||||
void should_throw_invariant_exception_if_customer_number_is_null() {
|
||||
Name name = new Name("Tester");
|
||||
MailAddress mailAddress = new MailAddress("tester@web.io");
|
||||
|
||||
assertThrows(InvariantException.class, () -> new Customer(null, name, mailAddress));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_invariant_exception_if_name_is_null() {
|
||||
MailAddress mailAddress = new MailAddress("tester@web.io");
|
||||
CustomerNumber customerNumber = new CustomerNumber("A-1");
|
||||
|
||||
assertThrows(InvariantException.class, () -> new Customer(customerNumber, null, mailAddress));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_invariant_exception_if_mail_is_null() {
|
||||
Name name = new Name("Tester");
|
||||
CustomerNumber customerNumber = new CustomerNumber("A-1");
|
||||
|
||||
assertThrows(InvariantException.class, () -> new Customer(customerNumber, name, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.weinbrecht.luc.bpm.architecture.recommendation.domain.service;
|
||||
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Content;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.ContentId;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.domain.model.Description;
|
||||
import de.weinbrecht.luc.bpm.architecture.recommendation.usecase.out.RecommendationQuery;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@MockitoSettings
|
||||
class RecommendationServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
private RecommendationService classUnderTest;
|
||||
|
||||
@Mock
|
||||
private RecommendationQuery recommendationQuery;
|
||||
|
||||
@Test
|
||||
void should_magically_pick_the_content() {
|
||||
ContentId contentId = new ContentId(1L);
|
||||
Content content = new Content(contentId, new Description("Test"));
|
||||
when(recommendationQuery.findContentById(contentId)).thenReturn(content);
|
||||
|
||||
ContentId result = classUnderTest.pickContent();
|
||||
|
||||
assertThat(result).isEqualTo(contentId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user