@reventlessdev/online-shop-hybrid-ordering 1.0.0-alpha.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +904 -0
- package/LICENSE +202 -0
- package/__mocks__/emptyModule.js +1 -0
- package/package.json +57 -0
- package/rescript.json +37 -0
- package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct.res +29 -0
- package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct.res.mjs +71 -0
- package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct_Behavior.res +27 -0
- package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct_Behavior.res.mjs +73 -0
- package/src/CatalogProduct/StateViewSliceStream/AvailableProducts.res +15 -0
- package/src/CatalogProduct/StateViewSliceStream/AvailableProducts.res.mjs +69 -0
- package/src/CatalogProduct/StateViewSliceStream/AvailableProducts_Projection.res +8 -0
- package/src/CatalogProduct/StateViewSliceStream/AvailableProducts_Projection.res.mjs +38 -0
- package/src/Customer/Aggregate/Customer.res +24 -0
- package/src/Customer/Aggregate/Customer.res.mjs +64 -0
- package/src/Customer/Aggregate/Customer_Behavior.res +41 -0
- package/src/Customer/Aggregate/Customer_Behavior.res.mjs +143 -0
- package/src/Customer/ReadModelStream/Customers.res +15 -0
- package/src/Customer/ReadModelStream/Customers.res.mjs +44 -0
- package/src/Customer/ReadModelStream/Customers_Projections.res +78 -0
- package/src/Customer/ReadModelStream/Customers_Projections.res.mjs +153 -0
- package/src/Extension/Products_Extension.res +23 -0
- package/src/Extension/Products_Extension.res.mjs +43 -0
- package/src/ExtensionPoint/Orders_ExtensionPointMapping.res +33 -0
- package/src/ExtensionPoint/Orders_ExtensionPointMapping.res.mjs +82 -0
- package/src/Order/AutomationSlice/AutoShipOrder.res +19 -0
- package/src/Order/AutomationSlice/AutoShipOrder.res.mjs +42 -0
- package/src/Order/AutomationSlice/AutoShipOrder_Automation.res +37 -0
- package/src/Order/AutomationSlice/AutoShipOrder_Automation.res.mjs +101 -0
- package/src/Order/OutboundTranslationSlice/SendOrderConfirmation.res +22 -0
- package/src/Order/OutboundTranslationSlice/SendOrderConfirmation.res.mjs +45 -0
- package/src/Order/OutboundTranslationSlice/SendOrderConfirmation_Translation.res +24 -0
- package/src/Order/OutboundTranslationSlice/SendOrderConfirmation_Translation.res.mjs +46 -0
- package/src/Order/StateChangeSlice/CancelOrder.res +29 -0
- package/src/Order/StateChangeSlice/CancelOrder.res.mjs +75 -0
- package/src/Order/StateChangeSlice/CancelOrder_Behavior.res +35 -0
- package/src/Order/StateChangeSlice/CancelOrder_Behavior.res.mjs +110 -0
- package/src/Order/StateChangeSlice/PlaceOrder.res +28 -0
- package/src/Order/StateChangeSlice/PlaceOrder.res.mjs +63 -0
- package/src/Order/StateChangeSlice/PlaceOrder_Behavior.res +39 -0
- package/src/Order/StateChangeSlice/PlaceOrder_Behavior.res.mjs +70 -0
- package/src/Order/StateChangeSlice/RefundOrder.res +27 -0
- package/src/Order/StateChangeSlice/RefundOrder.res.mjs +59 -0
- package/src/Order/StateChangeSlice/RefundOrder_Behavior.res +26 -0
- package/src/Order/StateChangeSlice/RefundOrder_Behavior.res.mjs +77 -0
- package/src/Order/StateChangeSlice/ShipOrder.res +23 -0
- package/src/Order/StateChangeSlice/ShipOrder.res.mjs +56 -0
- package/src/Order/StateChangeSlice/ShipOrder_Behavior.res +26 -0
- package/src/Order/StateChangeSlice/ShipOrder_Behavior.res.mjs +73 -0
- package/src/Order/StateViewSliceStream/Orders.res +24 -0
- package/src/Order/StateViewSliceStream/Orders.res.mjs +80 -0
- package/src/Order/StateViewSliceStream/Orders_Projection.res +10 -0
- package/src/Order/StateViewSliceStream/Orders_Projection.res.mjs +52 -0
- package/src/Plugin.res +74 -0
- package/src/Plugin.res.mjs +304 -0
- package/src/Service/EmailService.res +3 -0
- package/src/Service/EmailService.res.mjs +11 -0
- package/src/plugin.json +1 -0
- package/tests/CatalogProduct/StateChangeSlice/SyncCatalogProduct_GWT.res +27 -0
- package/tests/CatalogProduct/StateChangeSlice/SyncCatalogProduct_GWT.res.mjs +109 -0
- package/tests/CatalogProduct/StateViewSliceStream/AvailableProducts_GWT.res +15 -0
- package/tests/CatalogProduct/StateViewSliceStream/AvailableProducts_GWT.res.mjs +93 -0
- package/tests/Customer/Aggregate/Customer_GWT.res +63 -0
- package/tests/Customer/Aggregate/Customer_GWT.res.mjs +153 -0
- package/tests/Customer/ReadModelStream/Customers_GWT.res +84 -0
- package/tests/Customer/ReadModelStream/Customers_GWT.res.mjs +90 -0
- package/tests/Extension/Products_Extension_GWT.res +23 -0
- package/tests/Extension/Products_Extension_GWT.res.mjs +108 -0
- package/tests/ExtensionPoint/Orders_ExtensionPointMapping_GWT.res +23 -0
- package/tests/ExtensionPoint/Orders_ExtensionPointMapping_GWT.res.mjs +139 -0
- package/tests/Flow/OrderingFlow_GWT.res +69 -0
- package/tests/Flow/OrderingFlow_GWT.res.mjs +184 -0
- package/tests/Order/AutomationSlice/AutoShipOrder_GWT.res +55 -0
- package/tests/Order/AutomationSlice/AutoShipOrder_GWT.res.mjs +133 -0
- package/tests/Order/OutboundTranslationSlice/SendOrderConfirmation_GWT.res +30 -0
- package/tests/Order/OutboundTranslationSlice/SendOrderConfirmation_GWT.res.mjs +102 -0
- package/tests/Order/StateChangeSlice/CancelOrder_GWT.res +45 -0
- package/tests/Order/StateChangeSlice/CancelOrder_GWT.res.mjs +131 -0
- package/tests/Order/StateChangeSlice/PlaceOrder_GWT.res +33 -0
- package/tests/Order/StateChangeSlice/PlaceOrder_GWT.res.mjs +139 -0
- package/tests/Order/StateChangeSlice/RefundOrder_GWT.res +31 -0
- package/tests/Order/StateChangeSlice/RefundOrder_GWT.res.mjs +100 -0
- package/tests/Order/StateChangeSlice/ShipOrder_GWT.res +27 -0
- package/tests/Order/StateChangeSlice/ShipOrder_GWT.res.mjs +91 -0
- package/tests/Order/StateViewSliceStream/Orders_GWT.res +36 -0
- package/tests/Order/StateViewSliceStream/Orders_GWT.res.mjs +114 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
+
|
|
6
|
+
let eventSchema = S.union([
|
|
7
|
+
S.schema(s => ({
|
|
8
|
+
TAG: "OrderPlaced",
|
|
9
|
+
orderId: s.m(DcbTag$Reventless.string),
|
|
10
|
+
customerId: s.m(DcbTag$Reventless.string),
|
|
11
|
+
productIds: s.m(S.array(DcbTag$Reventless.stringForKey("productId")))
|
|
12
|
+
})),
|
|
13
|
+
S.schema(s => ({
|
|
14
|
+
TAG: "OrderCancelled",
|
|
15
|
+
orderId: s.m(DcbTag$Reventless.string),
|
|
16
|
+
productIds: s.m(S.array(DcbTag$Reventless.stringForKey("productId")))
|
|
17
|
+
}))
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
function commandAuthorization(param) {
|
|
21
|
+
return "AllowAuthenticated";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let Delegate = {
|
|
25
|
+
Id: undefined,
|
|
26
|
+
commandSchema: S.unit,
|
|
27
|
+
name: "OrderingDcbEventLog",
|
|
28
|
+
eventSchema: eventSchema,
|
|
29
|
+
errorSchema: S.unit,
|
|
30
|
+
moduleUrl: "@reventlessdev/online-shop-hybrid-ordering/src/ExtensionPoint/Orders_ExtensionPointMapping.res.mjs",
|
|
31
|
+
commandAuthorization: commandAuthorization
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function mapIncomingCommand(_id, _command, _meta) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let mapOutgoingEvent = (_id, event, _meta, _queryEngine) => {
|
|
39
|
+
if (event.TAG === "OrderPlaced") {
|
|
40
|
+
let customerId = event.customerId;
|
|
41
|
+
let orderId = event.orderId;
|
|
42
|
+
return event.productIds.map(pid => ({
|
|
43
|
+
TAG: "PublishEvent",
|
|
44
|
+
_0: pid,
|
|
45
|
+
_1: {
|
|
46
|
+
TAG: "ItemOrdered",
|
|
47
|
+
productId: pid,
|
|
48
|
+
orderId: orderId,
|
|
49
|
+
customerId: customerId
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
let orderId$1 = event.orderId;
|
|
54
|
+
return event.productIds.map(pid => ({
|
|
55
|
+
TAG: "PublishEvent",
|
|
56
|
+
_0: pid,
|
|
57
|
+
_1: {
|
|
58
|
+
TAG: "ItemOrderCancelled",
|
|
59
|
+
productId: pid,
|
|
60
|
+
orderId: orderId$1
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
let name = "Orders";
|
|
66
|
+
|
|
67
|
+
let Id;
|
|
68
|
+
|
|
69
|
+
let ExtensionPoint;
|
|
70
|
+
|
|
71
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/ExtensionPoint/Orders_ExtensionPointMapping.res.mjs";
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
name,
|
|
75
|
+
Id,
|
|
76
|
+
ExtensionPoint,
|
|
77
|
+
Delegate,
|
|
78
|
+
mapIncomingCommand,
|
|
79
|
+
mapOutgoingEvent,
|
|
80
|
+
moduleUrl,
|
|
81
|
+
}
|
|
82
|
+
/* eventSchema Not a pure module */
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// AutoShipOrder AutomationSlice.
|
|
2
|
+
// When OrderPlaced is emitted, automatically issue a ShipOrder command.
|
|
3
|
+
// Resolved when OrderShipped arrives.
|
|
4
|
+
//
|
|
5
|
+
// Consumed events come from per-source `Mapping.Make` modules in the sibling
|
|
6
|
+
// `_Automation.res`. The framework derives the consumed-event set from each
|
|
7
|
+
// mapping's `sourceEventSchema` — no manual union here.
|
|
8
|
+
|
|
9
|
+
@@reventless.spec
|
|
10
|
+
|
|
11
|
+
@schema
|
|
12
|
+
type todoItem = {orderId: string}
|
|
13
|
+
|
|
14
|
+
@schema
|
|
15
|
+
type command = ShipOrder({orderId: string})
|
|
16
|
+
|
|
17
|
+
let maxRetries = 3
|
|
18
|
+
let heartbeatInterval = 60
|
|
19
|
+
let targetName = "ShipOrder"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
+
|
|
6
|
+
let todoItemSchema = S.schema(s => ({
|
|
7
|
+
orderId: s.m(S.string)
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
let commandSchema = S.schema(s => ({
|
|
11
|
+
TAG: "ShipOrder",
|
|
12
|
+
orderId: s.m(DcbTag$Reventless.string)
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
function commandAuthorization(param) {
|
|
16
|
+
return "AllowAuthenticated";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let name = "AutoShipOrder";
|
|
20
|
+
|
|
21
|
+
let Id;
|
|
22
|
+
|
|
23
|
+
let maxRetries = 3;
|
|
24
|
+
|
|
25
|
+
let heartbeatInterval = 60;
|
|
26
|
+
|
|
27
|
+
let targetName = "ShipOrder";
|
|
28
|
+
|
|
29
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Order/AutomationSlice/AutoShipOrder.res.mjs";
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
name,
|
|
33
|
+
Id,
|
|
34
|
+
todoItemSchema,
|
|
35
|
+
commandSchema,
|
|
36
|
+
maxRetries,
|
|
37
|
+
heartbeatInterval,
|
|
38
|
+
targetName,
|
|
39
|
+
moduleUrl,
|
|
40
|
+
commandAuthorization,
|
|
41
|
+
}
|
|
42
|
+
/* todoItemSchema Not a pure module */
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
@@reventless.automation
|
|
2
|
+
|
|
3
|
+
// Single DCB source — events from the ordering plugin's own event log.
|
|
4
|
+
// `name` MUST equal `<pluginName>DcbEventLog` so the dispatch in
|
|
5
|
+
// `AutomationSlice_Callback` resolves it to the topic key `Plugin_Builder`
|
|
6
|
+
// registers under.
|
|
7
|
+
module OrderingDcbSource = {
|
|
8
|
+
let name = "OrderingDcbEventLog"
|
|
9
|
+
@schema
|
|
10
|
+
type event =
|
|
11
|
+
| OrderPlaced({orderId: string})
|
|
12
|
+
| OrderShipped({orderId: string})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module FromOrderingDcb = Mapping.Make(
|
|
16
|
+
OrderingDcbSource,
|
|
17
|
+
AutoShipOrder,
|
|
18
|
+
{
|
|
19
|
+
open OrderingDcbSource
|
|
20
|
+
|
|
21
|
+
let collect = (event, _ctx) =>
|
|
22
|
+
switch event {
|
|
23
|
+
| OrderPlaced({orderId}) => [(orderId, ({orderId: orderId}: AutoShipOrder.todoItem))]
|
|
24
|
+
| OrderShipped(_) => []
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let resolve = event =>
|
|
28
|
+
switch event {
|
|
29
|
+
| OrderShipped({orderId}) => Some(orderId)
|
|
30
|
+
| OrderPlaced(_) => None
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
let mappings: array<module(Mapping)> = [module(FromOrderingDcb)]
|
|
36
|
+
|
|
37
|
+
let process = (id, _item) => Some((id, ShipOrder({orderId: id})))
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
5
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
6
|
+
import * as AutomationSlice$Reventless from "@reventlessdev/reventless-spec/src/components/AutomationSlice.res.mjs";
|
|
7
|
+
import * as AutoShipOrder$OrderingPlugin from "./AutoShipOrder.res.mjs";
|
|
8
|
+
|
|
9
|
+
let M = AutomationSlice$Reventless.Mappings.Make({
|
|
10
|
+
name: AutoShipOrder$OrderingPlugin.name,
|
|
11
|
+
moduleUrl: AutoShipOrder$OrderingPlugin.moduleUrl,
|
|
12
|
+
todoItemSchema: AutoShipOrder$OrderingPlugin.todoItemSchema,
|
|
13
|
+
commandSchema: AutoShipOrder$OrderingPlugin.commandSchema,
|
|
14
|
+
maxRetries: AutoShipOrder$OrderingPlugin.maxRetries,
|
|
15
|
+
heartbeatInterval: AutoShipOrder$OrderingPlugin.heartbeatInterval,
|
|
16
|
+
targetName: AutoShipOrder$OrderingPlugin.targetName
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
let name = "OrderingDcbEventLog";
|
|
20
|
+
|
|
21
|
+
let eventSchema = S.union([
|
|
22
|
+
S.schema(s => ({
|
|
23
|
+
TAG: "OrderPlaced",
|
|
24
|
+
orderId: s.m(DcbTag$Reventless.string)
|
|
25
|
+
})),
|
|
26
|
+
S.schema(s => ({
|
|
27
|
+
TAG: "OrderShipped",
|
|
28
|
+
orderId: s.m(DcbTag$Reventless.string)
|
|
29
|
+
}))
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
let OrderingDcbSource = {
|
|
33
|
+
Id: undefined,
|
|
34
|
+
name: name,
|
|
35
|
+
eventSchema: eventSchema
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function collect(event, _ctx) {
|
|
39
|
+
if (event.TAG !== "OrderPlaced") {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
let orderId = event.orderId;
|
|
43
|
+
return [[
|
|
44
|
+
orderId,
|
|
45
|
+
{
|
|
46
|
+
orderId: orderId
|
|
47
|
+
}
|
|
48
|
+
]];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resolve(event) {
|
|
52
|
+
if (event.TAG === "OrderPlaced") {
|
|
53
|
+
return;
|
|
54
|
+
} else {
|
|
55
|
+
return event.orderId;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let FromOrderingDcb = AutomationSlice$Reventless.Mapping.Make({
|
|
60
|
+
Id: Id$Reventless.$$String,
|
|
61
|
+
name: name,
|
|
62
|
+
eventSchema: eventSchema
|
|
63
|
+
})({
|
|
64
|
+
name: AutoShipOrder$OrderingPlugin.name,
|
|
65
|
+
moduleUrl: AutoShipOrder$OrderingPlugin.moduleUrl,
|
|
66
|
+
todoItemSchema: AutoShipOrder$OrderingPlugin.todoItemSchema,
|
|
67
|
+
commandSchema: AutoShipOrder$OrderingPlugin.commandSchema,
|
|
68
|
+
maxRetries: AutoShipOrder$OrderingPlugin.maxRetries,
|
|
69
|
+
heartbeatInterval: AutoShipOrder$OrderingPlugin.heartbeatInterval,
|
|
70
|
+
targetName: AutoShipOrder$OrderingPlugin.targetName
|
|
71
|
+
})({
|
|
72
|
+
collect: collect,
|
|
73
|
+
resolve: resolve
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
let mappings = [FromOrderingDcb];
|
|
77
|
+
|
|
78
|
+
function process(id, _item) {
|
|
79
|
+
return [
|
|
80
|
+
id,
|
|
81
|
+
{
|
|
82
|
+
TAG: "ShipOrder",
|
|
83
|
+
orderId: id
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let Spec;
|
|
89
|
+
|
|
90
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Order/AutomationSlice/AutoShipOrder_Automation.res.mjs";
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
Spec,
|
|
94
|
+
M,
|
|
95
|
+
OrderingDcbSource,
|
|
96
|
+
FromOrderingDcb,
|
|
97
|
+
mappings,
|
|
98
|
+
process,
|
|
99
|
+
moduleUrl,
|
|
100
|
+
}
|
|
101
|
+
/* M Not a pure module */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// SendOrderConfirmation OutboundTranslationSlice.
|
|
2
|
+
// When OrderPlaced is emitted, sends a confirmation email via EmailService.
|
|
3
|
+
// Fire-and-forget pattern (no inbound command).
|
|
4
|
+
|
|
5
|
+
@@reventless.spec
|
|
6
|
+
|
|
7
|
+
@schema
|
|
8
|
+
type consumedEvent =
|
|
9
|
+
| OrderPlaced({orderId: string, customerId: string})
|
|
10
|
+
|
|
11
|
+
@schema
|
|
12
|
+
type outboundItem = {orderId: string, customerId: string}
|
|
13
|
+
|
|
14
|
+
@schema
|
|
15
|
+
type inboundCommand = unit
|
|
16
|
+
|
|
17
|
+
let maxRetries = 3
|
|
18
|
+
let heartbeatInterval = 60
|
|
19
|
+
let targetName = None
|
|
20
|
+
// Foreign system this anti-corruption slice publishes confirmations to — drawn as an
|
|
21
|
+
// external box outside the Ordering plugin in the Event Graph.
|
|
22
|
+
let externalSystem = Some("EmailService")
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
+
|
|
6
|
+
let consumedEventSchema = S.schema(s => ({
|
|
7
|
+
TAG: "OrderPlaced",
|
|
8
|
+
orderId: s.m(DcbTag$Reventless.string),
|
|
9
|
+
customerId: s.m(DcbTag$Reventless.string)
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
let outboundItemSchema = S.schema(s => ({
|
|
13
|
+
orderId: s.m(S.string),
|
|
14
|
+
customerId: s.m(S.string)
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
let name = "SendOrderConfirmation";
|
|
18
|
+
|
|
19
|
+
let Id;
|
|
20
|
+
|
|
21
|
+
let inboundCommandSchema = S.unit;
|
|
22
|
+
|
|
23
|
+
let maxRetries = 3;
|
|
24
|
+
|
|
25
|
+
let heartbeatInterval = 60;
|
|
26
|
+
|
|
27
|
+
let targetName;
|
|
28
|
+
|
|
29
|
+
let externalSystem = "EmailService";
|
|
30
|
+
|
|
31
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Order/OutboundTranslationSlice/SendOrderConfirmation.res.mjs";
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
name,
|
|
35
|
+
Id,
|
|
36
|
+
consumedEventSchema,
|
|
37
|
+
outboundItemSchema,
|
|
38
|
+
inboundCommandSchema,
|
|
39
|
+
maxRetries,
|
|
40
|
+
heartbeatInterval,
|
|
41
|
+
targetName,
|
|
42
|
+
externalSystem,
|
|
43
|
+
moduleUrl,
|
|
44
|
+
}
|
|
45
|
+
/* consumedEventSchema Not a pure module */
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@@reventless.translation
|
|
2
|
+
|
|
3
|
+
let collect = event =>
|
|
4
|
+
switch event {
|
|
5
|
+
| OrderPlaced({orderId, customerId}) => [(orderId, {orderId, customerId})]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let translate = async (_id, item) => {
|
|
9
|
+
try {
|
|
10
|
+
await EmailService.sendOrderConfirmation(
|
|
11
|
+
~email=item.customerId,
|
|
12
|
+
~orderId=item.orderId,
|
|
13
|
+
)
|
|
14
|
+
Ok(None)
|
|
15
|
+
} catch {
|
|
16
|
+
| exn =>
|
|
17
|
+
let msg =
|
|
18
|
+
exn
|
|
19
|
+
->JsExn.fromException
|
|
20
|
+
->Option.flatMap(JsExn.message)
|
|
21
|
+
->Option.getOr("email send failed")
|
|
22
|
+
Error(msg)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
6
|
+
import * as EmailService$OrderingPlugin from "../../Service/EmailService.res.mjs";
|
|
7
|
+
|
|
8
|
+
function collect(event) {
|
|
9
|
+
let orderId = event.orderId;
|
|
10
|
+
return [[
|
|
11
|
+
orderId,
|
|
12
|
+
{
|
|
13
|
+
orderId: orderId,
|
|
14
|
+
customerId: event.customerId
|
|
15
|
+
}
|
|
16
|
+
]];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function translate(_id, item) {
|
|
20
|
+
try {
|
|
21
|
+
await EmailService$OrderingPlugin.sendOrderConfirmation(item.customerId, item.orderId);
|
|
22
|
+
return {
|
|
23
|
+
TAG: "Ok",
|
|
24
|
+
_0: undefined
|
|
25
|
+
};
|
|
26
|
+
} catch (raw_exn) {
|
|
27
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
28
|
+
let msg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "email send failed");
|
|
29
|
+
return {
|
|
30
|
+
TAG: "Error",
|
|
31
|
+
_0: msg
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let Spec;
|
|
37
|
+
|
|
38
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Order/OutboundTranslationSlice/SendOrderConfirmation_Translation.res.mjs";
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
Spec,
|
|
42
|
+
collect,
|
|
43
|
+
translate,
|
|
44
|
+
moduleUrl,
|
|
45
|
+
}
|
|
46
|
+
/* Stdlib_JsExn Not a pure module */
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// CancelOrder StateChangeSlice.
|
|
2
|
+
// Requires order to exist and not be shipped; idempotent if already cancelled.
|
|
3
|
+
|
|
4
|
+
@@reventless.spec
|
|
5
|
+
|
|
6
|
+
@schema
|
|
7
|
+
type consumedEvent =
|
|
8
|
+
| OrderPlaced({productIds: array<string>})
|
|
9
|
+
| OrderShipped
|
|
10
|
+
| OrderCancelled
|
|
11
|
+
| OrderReopened
|
|
12
|
+
|
|
13
|
+
@schema
|
|
14
|
+
type command =
|
|
15
|
+
| @allowedStates([Orders.Placed]) CancelOrder({orderId: string})
|
|
16
|
+
| @noApi ReopenOrder({orderId: string}) // Internal: admin/automation only
|
|
17
|
+
|
|
18
|
+
@schema
|
|
19
|
+
type error =
|
|
20
|
+
| OrderNotFound
|
|
21
|
+
| OrderAlreadyShipped
|
|
22
|
+
|
|
23
|
+
@schema
|
|
24
|
+
type event =
|
|
25
|
+
| OrderCancelled({
|
|
26
|
+
orderId: string,
|
|
27
|
+
productIds: array<string>,
|
|
28
|
+
})
|
|
29
|
+
| OrderReopened({orderId: string})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
+
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
6
|
+
|
|
7
|
+
let consumedEventSchema = S.union([
|
|
8
|
+
S.schema(s => ({
|
|
9
|
+
TAG: "OrderPlaced",
|
|
10
|
+
productIds: s.m(S.array(DcbTag$Reventless.stringForKey("productId")))
|
|
11
|
+
})),
|
|
12
|
+
S.literal("OrderShipped"),
|
|
13
|
+
S.literal("OrderCancelled"),
|
|
14
|
+
S.literal("OrderReopened")
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
let commandSchema = S.union([
|
|
18
|
+
S.schema(s => ({
|
|
19
|
+
TAG: "CancelOrder",
|
|
20
|
+
orderId: s.m(DcbTag$Reventless.string)
|
|
21
|
+
})),
|
|
22
|
+
S.schema(s => ({
|
|
23
|
+
TAG: "ReopenOrder",
|
|
24
|
+
orderId: s.m(DcbTag$Reventless.string)
|
|
25
|
+
}))
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
let errorSchema = S.union([
|
|
29
|
+
S.literal("OrderNotFound"),
|
|
30
|
+
S.literal("OrderAlreadyShipped")
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
let eventSchema = S.union([
|
|
34
|
+
S.schema(s => ({
|
|
35
|
+
TAG: "OrderCancelled",
|
|
36
|
+
orderId: s.m(DcbTag$Reventless.string),
|
|
37
|
+
productIds: s.m(S.array(DcbTag$Reventless.stringForKey("productId")))
|
|
38
|
+
})),
|
|
39
|
+
S.schema(s => ({
|
|
40
|
+
TAG: "OrderReopened",
|
|
41
|
+
orderId: s.m(DcbTag$Reventless.string)
|
|
42
|
+
}))
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
let commandSchema$1 = Api$ReventlessInfra.markNoApiVariants(commandSchema, ["ReopenOrder"]);
|
|
46
|
+
|
|
47
|
+
let commandSchema$2 = Api$ReventlessInfra.markAllowedStates(commandSchema$1, [[
|
|
48
|
+
"CancelOrder",
|
|
49
|
+
["Placed"]
|
|
50
|
+
]]);
|
|
51
|
+
|
|
52
|
+
function commandAuthorization(param) {
|
|
53
|
+
return "AllowAuthenticated";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let name = "CancelOrder";
|
|
57
|
+
|
|
58
|
+
let Id;
|
|
59
|
+
|
|
60
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Order/StateChangeSlice/CancelOrder.res.mjs";
|
|
61
|
+
|
|
62
|
+
let readConsistency = "EscalateOnRetry";
|
|
63
|
+
|
|
64
|
+
export {
|
|
65
|
+
name,
|
|
66
|
+
Id,
|
|
67
|
+
consumedEventSchema,
|
|
68
|
+
errorSchema,
|
|
69
|
+
eventSchema,
|
|
70
|
+
commandSchema$2 as commandSchema,
|
|
71
|
+
moduleUrl,
|
|
72
|
+
commandAuthorization,
|
|
73
|
+
readConsistency,
|
|
74
|
+
}
|
|
75
|
+
/* consumedEventSchema Not a pure module */
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@@reventless.behavior
|
|
2
|
+
|
|
3
|
+
type state = {exists: bool, shipped: bool, cancelled: bool, productIds: array<string>}
|
|
4
|
+
|
|
5
|
+
let initialState = {exists: false, shipped: false, cancelled: false, productIds: []}
|
|
6
|
+
|
|
7
|
+
let evolve = (state, event) =>
|
|
8
|
+
switch event {
|
|
9
|
+
| OrderPlaced({productIds}) => {exists: true, shipped: false, cancelled: false, productIds}
|
|
10
|
+
| OrderShipped => {...state, shipped: true}
|
|
11
|
+
| OrderCancelled => {...state, cancelled: true}
|
|
12
|
+
| OrderReopened => {...state, cancelled: false}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let decide = (state, command) =>
|
|
16
|
+
switch command {
|
|
17
|
+
| CancelOrder({orderId: theId}) =>
|
|
18
|
+
if !state.exists {
|
|
19
|
+
Error(OrderNotFound)
|
|
20
|
+
} else if state.shipped {
|
|
21
|
+
Error(OrderAlreadyShipped)
|
|
22
|
+
} else if state.cancelled {
|
|
23
|
+
Ok([]) // idempotent — already cancelled
|
|
24
|
+
} else {
|
|
25
|
+
Ok([OrderCancelled({orderId: theId, productIds: state.productIds})])
|
|
26
|
+
}
|
|
27
|
+
| ReopenOrder({orderId: theId}) =>
|
|
28
|
+
if !state.exists {
|
|
29
|
+
Error(OrderNotFound)
|
|
30
|
+
} else if !state.cancelled {
|
|
31
|
+
Ok([]) // idempotent — not cancelled
|
|
32
|
+
} else {
|
|
33
|
+
Ok([OrderReopened({orderId: theId})])
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
let initialState_productIds = [];
|
|
5
|
+
|
|
6
|
+
let initialState = {
|
|
7
|
+
exists: false,
|
|
8
|
+
shipped: false,
|
|
9
|
+
cancelled: false,
|
|
10
|
+
productIds: initialState_productIds
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function evolve(state, event) {
|
|
14
|
+
if (typeof event === "object") {
|
|
15
|
+
return {
|
|
16
|
+
exists: true,
|
|
17
|
+
shipped: false,
|
|
18
|
+
cancelled: false,
|
|
19
|
+
productIds: event.productIds
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
switch (event) {
|
|
23
|
+
case "OrderShipped" :
|
|
24
|
+
return {
|
|
25
|
+
exists: state.exists,
|
|
26
|
+
shipped: true,
|
|
27
|
+
cancelled: state.cancelled,
|
|
28
|
+
productIds: state.productIds
|
|
29
|
+
};
|
|
30
|
+
case "OrderCancelled" :
|
|
31
|
+
return {
|
|
32
|
+
exists: state.exists,
|
|
33
|
+
shipped: state.shipped,
|
|
34
|
+
cancelled: true,
|
|
35
|
+
productIds: state.productIds
|
|
36
|
+
};
|
|
37
|
+
case "OrderReopened" :
|
|
38
|
+
return {
|
|
39
|
+
exists: state.exists,
|
|
40
|
+
shipped: state.shipped,
|
|
41
|
+
cancelled: false,
|
|
42
|
+
productIds: state.productIds
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function decide(state, command) {
|
|
48
|
+
if (command.TAG === "CancelOrder") {
|
|
49
|
+
if (state.exists) {
|
|
50
|
+
if (state.shipped) {
|
|
51
|
+
return {
|
|
52
|
+
TAG: "Error",
|
|
53
|
+
_0: "OrderAlreadyShipped"
|
|
54
|
+
};
|
|
55
|
+
} else if (state.cancelled) {
|
|
56
|
+
return {
|
|
57
|
+
TAG: "Ok",
|
|
58
|
+
_0: []
|
|
59
|
+
};
|
|
60
|
+
} else {
|
|
61
|
+
return {
|
|
62
|
+
TAG: "Ok",
|
|
63
|
+
_0: [{
|
|
64
|
+
TAG: "OrderCancelled",
|
|
65
|
+
orderId: command.orderId,
|
|
66
|
+
productIds: state.productIds
|
|
67
|
+
}]
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
return {
|
|
72
|
+
TAG: "Error",
|
|
73
|
+
_0: "OrderNotFound"
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
} else if (state.exists) {
|
|
77
|
+
if (state.cancelled) {
|
|
78
|
+
return {
|
|
79
|
+
TAG: "Ok",
|
|
80
|
+
_0: [{
|
|
81
|
+
TAG: "OrderReopened",
|
|
82
|
+
orderId: command.orderId
|
|
83
|
+
}]
|
|
84
|
+
};
|
|
85
|
+
} else {
|
|
86
|
+
return {
|
|
87
|
+
TAG: "Ok",
|
|
88
|
+
_0: []
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
return {
|
|
93
|
+
TAG: "Error",
|
|
94
|
+
_0: "OrderNotFound"
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let Spec;
|
|
100
|
+
|
|
101
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Order/StateChangeSlice/CancelOrder_Behavior.res.mjs";
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
Spec,
|
|
105
|
+
initialState,
|
|
106
|
+
evolve,
|
|
107
|
+
decide,
|
|
108
|
+
moduleUrl,
|
|
109
|
+
}
|
|
110
|
+
/* No side effect */
|