@reventlessdev/online-shop-hybrid-ordering 1.0.0-alpha.262 → 1.0.0-alpha.264
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 +22 -0
- package/package.json +10 -10
- package/src/Customer/ReadModelStream/Customers.res +1 -1
- package/src/Customer/ReadModelStream/Customers.res.mjs +1 -1
- package/src/Order/StateChange/CancelOrder.res +4 -1
- package/src/Order/StateChange/CancelOrder.res.mjs +4 -1
- package/src/Order/StateChange/ShipOrder.res +1 -1
- package/src/Order/StateChange/ShipOrder.res.mjs +1 -1
- package/src/Roles.res +5 -0
- package/src/Roles.res.mjs +2 -0
- package/tests/CatalogProduct/StateChange/SyncCatalogProduct_GWT.res.mjs +11 -1
- package/tests/Customer/AddressGeocodingConformance_GWT.res.mjs +4 -2
- package/tests/Customer/Aggregate/Customer_GWT.res.mjs +13 -2
- package/tests/Customer/StateChange/EmailVerificationChallenges_GWT.res.mjs +11 -1
- package/tests/Flow/OrderingFlow_GWT.res.mjs +6 -3
- package/tests/Notification/NotificationConformance_GWT.res.mjs +4 -2
- package/tests/Notification/StateChange/NotificationPreferences_GWT.res.mjs +11 -1
- package/tests/Notification/StateChange/NotificationSourceClaims_GWT.res.mjs +11 -1
- package/tests/Order/StateChange/CancelOrder_GWT.res +41 -6
- package/tests/Order/StateChange/CancelOrder_GWT.res.mjs +63 -7
- package/tests/Order/StateChange/PlaceOrder_GWT.res.mjs +11 -1
- package/tests/Order/StateChange/ShipOrder_GWT.res +34 -0
- package/tests/Order/StateChange/ShipOrder_GWT.res.mjs +54 -1
- package/tests/Ordering_Examples.res +1 -0
- package/tests/Ordering_Examples.res.mjs +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 1.0.0-alpha.264 (2026-10-01)
|
|
7
|
+
|
|
8
|
+
* feat!: roles a plugin declares, groups a platform provides ([43daace](https://github.com/ReventlessDev/reventless-core/commit/43daace6ca588afe22562d079af1e6f1da81942e))
|
|
9
|
+
|
|
10
|
+
### BREAKING CHANGES
|
|
11
|
+
|
|
12
|
+
* AllowGroups and AdminGroup are removed — write AllowRoles over
|
|
13
|
+
the plugin's Roles.t, and use Role.admin / Platform.adminGroup(). Spec module
|
|
14
|
+
types declare `type role`, and their rules are Authorization.rule<role>; a spec
|
|
15
|
+
that writes its own rule declares `type role` (Reventless.Role.name for a rule
|
|
16
|
+
over Authorization.permission). Role.name is a private string: make one from a
|
|
17
|
+
string with Role.make.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# 1.0.0-alpha.263 (2026-10-01)
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
* **spec, core, gwt, ppx:** a command acts only on what its caller owns ([2636f0e](https://github.com/ReventlessDev/reventless-core/commit/2636f0ee44797ee2c0b0c40a7107cf306113173f))
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
# 1.0.0-alpha.262 (2026-09-29)
|
|
7
29
|
|
|
8
30
|
**Note:** Version bump only for package @reventlessdev/online-shop-hybrid-ordering
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/online-shop-hybrid-ordering",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.264",
|
|
4
4
|
"description": "Online Shop Hybrid example — Ordering plugin (Customer aggregate + Order/CatalogProduct DCB)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -21,20 +21,20 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"sury": "11.0.0",
|
|
24
|
-
"@reventlessdev/online-shop-hybrid-
|
|
25
|
-
"@reventlessdev/online-shop-hybrid-catalog-spec": "1.0.0-alpha.151",
|
|
24
|
+
"@reventlessdev/online-shop-hybrid-catalog-spec": "1.0.0-alpha.153",
|
|
26
25
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.22",
|
|
27
|
-
"@reventlessdev/
|
|
28
|
-
"@reventlessdev/reventless-
|
|
29
|
-
"@reventlessdev/reventless-
|
|
30
|
-
"@reventlessdev/reventless-
|
|
31
|
-
"@reventlessdev/
|
|
32
|
-
"@reventlessdev/trait-
|
|
26
|
+
"@reventlessdev/online-shop-hybrid-ordering-spec": "1.0.0-alpha.152",
|
|
27
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.233",
|
|
28
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.184",
|
|
29
|
+
"@reventlessdev/reventless-local": "3.0.0-alpha.276",
|
|
30
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.156",
|
|
31
|
+
"@reventlessdev/trait-address-geocoding": "1.0.0-alpha.35",
|
|
32
|
+
"@reventlessdev/trait-notification": "1.0.0-alpha.35"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"rescript": "12.3.1",
|
|
36
36
|
"sury-ppx": "11.0.0",
|
|
37
|
-
"@reventlessdev/reventless-ppx": "1.0.0-alpha.
|
|
37
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.96"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"rescript": "^12.3.1"
|
|
@@ -7,7 +7,7 @@ module Id = CustomerId
|
|
|
7
7
|
|
|
8
8
|
// Operator surface: everyone's profile, so operator-only. A shopper reads their
|
|
9
9
|
// own orders instead.
|
|
10
|
-
@@reventless.authorize(
|
|
10
|
+
@@reventless.authorize(AllowRoles([Admin, Fulfilment]))
|
|
11
11
|
|
|
12
12
|
// A state rather than a flag beside one, so a command can say where it belongs:
|
|
13
13
|
// `Moves([Deactivated], Active)` on `Reactivate`. `@retired` withdraws
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
@@reventless.spec
|
|
5
5
|
|
|
6
|
+
// `@owner` on the consumed `customerId` says whose order this is. The framework
|
|
7
|
+
// reads it before `decide` and refuses a shopper cancelling someone else's order;
|
|
8
|
+
// an operator, or an automation, still acts on anyone's.
|
|
6
9
|
@schema
|
|
7
10
|
type consumedEvent =
|
|
8
|
-
| OrderPlaced({productIds: array<CatalogSpec.ProductId.t
|
|
11
|
+
| OrderPlaced({productIds: array<CatalogSpec.ProductId.t>, @owner customerId: CustomerId.t})
|
|
9
12
|
| OrderShipped
|
|
10
13
|
| OrderCancelled
|
|
11
14
|
| OrderReopened
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Sury from "sury";
|
|
4
|
+
import * as Owner$Reventless from "@reventlessdev/reventless-spec/src/components/Owner.res.mjs";
|
|
4
5
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
6
|
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
6
7
|
import * as ProductId$CatalogSpec from "@reventlessdev/online-shop-hybrid-catalog-spec/src/ProductId.res.mjs";
|
|
7
8
|
import * as OrderId$OrderingPlugin from "../OrderId.res.mjs";
|
|
9
|
+
import * as CustomerId$OrderingPlugin from "../../Customer/CustomerId.res.mjs";
|
|
8
10
|
|
|
9
11
|
let consumedEventSchema = Sury.union([
|
|
10
12
|
Sury.$schema(s => ({
|
|
11
13
|
TAG: "OrderPlaced",
|
|
12
|
-
productIds: s.m(Sury.array(DcbTag$Reventless.mark(ProductId$CatalogSpec.schema)))
|
|
14
|
+
productIds: s.m(Sury.array(DcbTag$Reventless.mark(ProductId$CatalogSpec.schema))),
|
|
15
|
+
customerId: s.m(Owner$Reventless.mark(DcbTag$Reventless.mark(CustomerId$OrderingPlugin.schema)))
|
|
13
16
|
})),
|
|
14
17
|
Sury.literal("OrderShipped"),
|
|
15
18
|
Sury.literal("OrderCancelled"),
|
|
@@ -29,7 +29,7 @@ type consumedEvent =
|
|
|
29
29
|
| OrderReopened
|
|
30
30
|
|
|
31
31
|
@schema
|
|
32
|
-
type command = | @authorize(
|
|
32
|
+
type command = | @authorize(AllowRoles([Admin, Fulfilment])) ShipOrder({orderId: OrderId.t})
|
|
33
33
|
|
|
34
34
|
@schema
|
|
35
35
|
type error =
|
package/src/Roles.res
ADDED
|
@@ -10,7 +10,8 @@ let include = Behavior_GWT$ReventlessGwt.Make({
|
|
|
10
10
|
consumedEventSchema: SyncCatalogProduct$OrderingPlugin.consumedEventSchema,
|
|
11
11
|
commandSchema: SyncCatalogProduct$OrderingPlugin.commandSchema,
|
|
12
12
|
errorSchema: SyncCatalogProduct$OrderingPlugin.errorSchema,
|
|
13
|
-
eventSchema: SyncCatalogProduct$OrderingPlugin.eventSchema
|
|
13
|
+
eventSchema: SyncCatalogProduct$OrderingPlugin.eventSchema,
|
|
14
|
+
commandAuthorization: SyncCatalogProduct$OrderingPlugin.commandAuthorization
|
|
14
15
|
})({
|
|
15
16
|
initialState: SyncCatalogProduct_Behavior$OrderingPlugin.initialState,
|
|
16
17
|
evolve: SyncCatalogProduct_Behavior$OrderingPlugin.evolve,
|
|
@@ -149,6 +150,10 @@ let Spec = include.Spec;
|
|
|
149
150
|
|
|
150
151
|
let todo = include.todo;
|
|
151
152
|
|
|
153
|
+
let Caller = include.Caller;
|
|
154
|
+
|
|
155
|
+
let asCaller = include.asCaller;
|
|
156
|
+
|
|
152
157
|
let thenEvents = include.thenEvents;
|
|
153
158
|
|
|
154
159
|
let thenEventWithError = include.thenEventWithError;
|
|
@@ -157,6 +162,8 @@ let thenEventsWithError = include.thenEventsWithError;
|
|
|
157
162
|
|
|
158
163
|
let thenError = include.thenError;
|
|
159
164
|
|
|
165
|
+
let thenRefused = include.thenRefused;
|
|
166
|
+
|
|
160
167
|
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
161
168
|
|
|
162
169
|
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
@@ -167,6 +174,8 @@ export {
|
|
|
167
174
|
todo,
|
|
168
175
|
test,
|
|
169
176
|
givenEvents,
|
|
177
|
+
Caller,
|
|
178
|
+
asCaller,
|
|
170
179
|
whenCmd,
|
|
171
180
|
thenEvent,
|
|
172
181
|
thenEvents,
|
|
@@ -174,6 +183,7 @@ export {
|
|
|
174
183
|
thenEventWithError,
|
|
175
184
|
thenEventsWithError,
|
|
176
185
|
thenError,
|
|
186
|
+
thenRefused,
|
|
177
187
|
thenAppendsConditionedOn,
|
|
178
188
|
thenAppendsConditionedOnExactly,
|
|
179
189
|
}
|
|
@@ -147,14 +147,16 @@ let Conformance = AddressGeocoding_Conformance$TraitAddressGeocoding.Make({
|
|
|
147
147
|
name: Customer$OrderingPlugin.name,
|
|
148
148
|
commandSchema: Customer$OrderingPlugin.commandSchema,
|
|
149
149
|
eventSchema: Customer$OrderingPlugin.eventSchema,
|
|
150
|
-
errorSchema: Customer$OrderingPlugin.errorSchema
|
|
150
|
+
errorSchema: Customer$OrderingPlugin.errorSchema,
|
|
151
|
+
commandAuthorization: Customer$OrderingPlugin.commandAuthorization
|
|
151
152
|
},
|
|
152
153
|
Behavior: {
|
|
153
154
|
Spec: {
|
|
154
155
|
name: Customer$OrderingPlugin.name,
|
|
155
156
|
commandSchema: Customer$OrderingPlugin.commandSchema,
|
|
156
157
|
eventSchema: Customer$OrderingPlugin.eventSchema,
|
|
157
|
-
errorSchema: Customer$OrderingPlugin.errorSchema
|
|
158
|
+
errorSchema: Customer$OrderingPlugin.errorSchema,
|
|
159
|
+
commandAuthorization: Customer$OrderingPlugin.commandAuthorization
|
|
158
160
|
},
|
|
159
161
|
initialState: Customer_Behavior$OrderingPlugin.initialState,
|
|
160
162
|
evolve: Customer_Behavior$OrderingPlugin.evolve,
|
|
@@ -9,13 +9,15 @@ let include = Behavior_GWT$ReventlessGwt.MakeFromAggregate({
|
|
|
9
9
|
name: Customer$OrderingPlugin.name,
|
|
10
10
|
commandSchema: Customer$OrderingPlugin.commandSchema,
|
|
11
11
|
eventSchema: Customer$OrderingPlugin.eventSchema,
|
|
12
|
-
errorSchema: Customer$OrderingPlugin.errorSchema
|
|
12
|
+
errorSchema: Customer$OrderingPlugin.errorSchema,
|
|
13
|
+
commandAuthorization: Customer$OrderingPlugin.commandAuthorization
|
|
13
14
|
})({
|
|
14
15
|
Spec: {
|
|
15
16
|
name: Customer$OrderingPlugin.name,
|
|
16
17
|
commandSchema: Customer$OrderingPlugin.commandSchema,
|
|
17
18
|
eventSchema: Customer$OrderingPlugin.eventSchema,
|
|
18
|
-
errorSchema: Customer$OrderingPlugin.errorSchema
|
|
19
|
+
errorSchema: Customer$OrderingPlugin.errorSchema,
|
|
20
|
+
commandAuthorization: Customer$OrderingPlugin.commandAuthorization
|
|
19
21
|
},
|
|
20
22
|
initialState: Customer_Behavior$OrderingPlugin.initialState,
|
|
21
23
|
evolve: Customer_Behavior$OrderingPlugin.evolve,
|
|
@@ -278,6 +280,10 @@ describe("Customer email verification", () => {
|
|
|
278
280
|
|
|
279
281
|
let Spec = include.Spec;
|
|
280
282
|
|
|
283
|
+
let Caller = include.Caller;
|
|
284
|
+
|
|
285
|
+
let asCaller = include.asCaller;
|
|
286
|
+
|
|
281
287
|
let thenCompareEvent = include.thenCompareEvent;
|
|
282
288
|
|
|
283
289
|
let thenEventWithError = include.thenEventWithError;
|
|
@@ -288,11 +294,15 @@ let thenCompareEvents = include.thenCompareEvents;
|
|
|
288
294
|
|
|
289
295
|
let thenEventsWithError = include.thenEventsWithError;
|
|
290
296
|
|
|
297
|
+
let thenRefused = include.thenRefused;
|
|
298
|
+
|
|
291
299
|
export {
|
|
292
300
|
Spec,
|
|
293
301
|
describe,
|
|
294
302
|
test,
|
|
295
303
|
givenEvents,
|
|
304
|
+
Caller,
|
|
305
|
+
asCaller,
|
|
296
306
|
whenCmd,
|
|
297
307
|
thenEvent,
|
|
298
308
|
thenCompareEvent,
|
|
@@ -302,5 +312,6 @@ export {
|
|
|
302
312
|
thenCompareEvents,
|
|
303
313
|
thenEventsWithError,
|
|
304
314
|
thenError,
|
|
315
|
+
thenRefused,
|
|
305
316
|
}
|
|
306
317
|
/* include Not a pure module */
|
|
@@ -10,7 +10,8 @@ let include = Behavior_GWT$ReventlessGwt.Make({
|
|
|
10
10
|
consumedEventSchema: EmailVerificationChallenges$OrderingPlugin.consumedEventSchema,
|
|
11
11
|
commandSchema: EmailVerificationChallenges$OrderingPlugin.commandSchema,
|
|
12
12
|
errorSchema: EmailVerificationChallenges$OrderingPlugin.errorSchema,
|
|
13
|
-
eventSchema: EmailVerificationChallenges$OrderingPlugin.eventSchema
|
|
13
|
+
eventSchema: EmailVerificationChallenges$OrderingPlugin.eventSchema,
|
|
14
|
+
commandAuthorization: EmailVerificationChallenges$OrderingPlugin.commandAuthorization
|
|
14
15
|
})({
|
|
15
16
|
initialState: EmailVerificationChallenges_Behavior$OrderingPlugin.initialState,
|
|
16
17
|
evolve: EmailVerificationChallenges_Behavior$OrderingPlugin.evolve,
|
|
@@ -161,12 +162,18 @@ let Spec = include.Spec;
|
|
|
161
162
|
|
|
162
163
|
let todo = include.todo;
|
|
163
164
|
|
|
165
|
+
let Caller = include.Caller;
|
|
166
|
+
|
|
167
|
+
let asCaller = include.asCaller;
|
|
168
|
+
|
|
164
169
|
let thenEvents = include.thenEvents;
|
|
165
170
|
|
|
166
171
|
let thenEventWithError = include.thenEventWithError;
|
|
167
172
|
|
|
168
173
|
let thenEventsWithError = include.thenEventsWithError;
|
|
169
174
|
|
|
175
|
+
let thenRefused = include.thenRefused;
|
|
176
|
+
|
|
170
177
|
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
171
178
|
|
|
172
179
|
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
@@ -177,6 +184,8 @@ export {
|
|
|
177
184
|
todo,
|
|
178
185
|
test,
|
|
179
186
|
givenEvents,
|
|
187
|
+
Caller,
|
|
188
|
+
asCaller,
|
|
180
189
|
whenCmd,
|
|
181
190
|
thenEvent,
|
|
182
191
|
thenEvents,
|
|
@@ -184,6 +193,7 @@ export {
|
|
|
184
193
|
thenEventWithError,
|
|
185
194
|
thenEventsWithError,
|
|
186
195
|
thenError,
|
|
196
|
+
thenRefused,
|
|
187
197
|
thenAppendsConditionedOn,
|
|
188
198
|
thenAppendsConditionedOnExactly,
|
|
189
199
|
issuedAt,
|
|
@@ -95,7 +95,8 @@ let Sync = Flow_GWT$ReventlessGwt.CommandStep({
|
|
|
95
95
|
consumedEventSchema: SyncCatalogProduct$OrderingPlugin.consumedEventSchema,
|
|
96
96
|
commandSchema: SyncCatalogProduct$OrderingPlugin.commandSchema,
|
|
97
97
|
errorSchema: SyncCatalogProduct$OrderingPlugin.errorSchema,
|
|
98
|
-
eventSchema: SyncCatalogProduct$OrderingPlugin.eventSchema
|
|
98
|
+
eventSchema: SyncCatalogProduct$OrderingPlugin.eventSchema,
|
|
99
|
+
commandAuthorization: SyncCatalogProduct$OrderingPlugin.commandAuthorization
|
|
99
100
|
})({
|
|
100
101
|
initialState: SyncCatalogProduct_Behavior$OrderingPlugin.initialState,
|
|
101
102
|
evolve: SyncCatalogProduct_Behavior$OrderingPlugin.evolve,
|
|
@@ -107,7 +108,8 @@ let Place = Flow_GWT$ReventlessGwt.CommandStep({
|
|
|
107
108
|
consumedEventSchema: PlaceOrder$OrderingPlugin.consumedEventSchema,
|
|
108
109
|
commandSchema: PlaceOrder$OrderingPlugin.commandSchema,
|
|
109
110
|
errorSchema: PlaceOrder$OrderingPlugin.errorSchema,
|
|
110
|
-
eventSchema: PlaceOrder$OrderingPlugin.eventSchema
|
|
111
|
+
eventSchema: PlaceOrder$OrderingPlugin.eventSchema,
|
|
112
|
+
commandAuthorization: PlaceOrder$OrderingPlugin.commandAuthorization
|
|
111
113
|
})({
|
|
112
114
|
initialState: PlaceOrder_Behavior$OrderingPlugin.initialState,
|
|
113
115
|
evolve: PlaceOrder_Behavior$OrderingPlugin.evolve,
|
|
@@ -129,7 +131,8 @@ let Ship = Flow_GWT$ReventlessGwt.CommandStep({
|
|
|
129
131
|
consumedEventSchema: ShipOrder$OrderingPlugin.consumedEventSchema,
|
|
130
132
|
commandSchema: ShipOrder$OrderingPlugin.commandSchema,
|
|
131
133
|
errorSchema: ShipOrder$OrderingPlugin.errorSchema,
|
|
132
|
-
eventSchema: ShipOrder$OrderingPlugin.eventSchema
|
|
134
|
+
eventSchema: ShipOrder$OrderingPlugin.eventSchema,
|
|
135
|
+
commandAuthorization: ShipOrder$OrderingPlugin.commandAuthorization
|
|
133
136
|
})({
|
|
134
137
|
initialState: ShipOrder_Behavior$OrderingPlugin.initialState,
|
|
135
138
|
evolve: ShipOrder_Behavior$OrderingPlugin.evolve,
|
|
@@ -248,7 +248,8 @@ let Conformance = Notification_Conformance$TraitNotification.Make({
|
|
|
248
248
|
consumedEventSchema: NotificationPreferences$OrderingPlugin.consumedEventSchema,
|
|
249
249
|
commandSchema: NotificationPreferences$OrderingPlugin.commandSchema,
|
|
250
250
|
errorSchema: NotificationPreferences$OrderingPlugin.errorSchema,
|
|
251
|
-
eventSchema: NotificationPreferences$OrderingPlugin.eventSchema
|
|
251
|
+
eventSchema: NotificationPreferences$OrderingPlugin.eventSchema,
|
|
252
|
+
commandAuthorization: NotificationPreferences$OrderingPlugin.commandAuthorization
|
|
252
253
|
},
|
|
253
254
|
Behavior: {
|
|
254
255
|
Spec: {
|
|
@@ -256,7 +257,8 @@ let Conformance = Notification_Conformance$TraitNotification.Make({
|
|
|
256
257
|
consumedEventSchema: NotificationPreferences$OrderingPlugin.consumedEventSchema,
|
|
257
258
|
commandSchema: NotificationPreferences$OrderingPlugin.commandSchema,
|
|
258
259
|
errorSchema: NotificationPreferences$OrderingPlugin.errorSchema,
|
|
259
|
-
eventSchema: NotificationPreferences$OrderingPlugin.eventSchema
|
|
260
|
+
eventSchema: NotificationPreferences$OrderingPlugin.eventSchema,
|
|
261
|
+
commandAuthorization: NotificationPreferences$OrderingPlugin.commandAuthorization
|
|
260
262
|
},
|
|
261
263
|
initialState: NotificationPreferences_Behavior$OrderingPlugin.initialState,
|
|
262
264
|
evolve: NotificationPreferences_Behavior$OrderingPlugin.evolve,
|
|
@@ -10,7 +10,8 @@ let include = Behavior_GWT$ReventlessGwt.Make({
|
|
|
10
10
|
consumedEventSchema: NotificationPreferences$OrderingPlugin.consumedEventSchema,
|
|
11
11
|
commandSchema: NotificationPreferences$OrderingPlugin.commandSchema,
|
|
12
12
|
errorSchema: NotificationPreferences$OrderingPlugin.errorSchema,
|
|
13
|
-
eventSchema: NotificationPreferences$OrderingPlugin.eventSchema
|
|
13
|
+
eventSchema: NotificationPreferences$OrderingPlugin.eventSchema,
|
|
14
|
+
commandAuthorization: NotificationPreferences$OrderingPlugin.commandAuthorization
|
|
14
15
|
})({
|
|
15
16
|
initialState: NotificationPreferences_Behavior$OrderingPlugin.initialState,
|
|
16
17
|
evolve: NotificationPreferences_Behavior$OrderingPlugin.evolve,
|
|
@@ -105,6 +106,10 @@ let Spec = include.Spec;
|
|
|
105
106
|
|
|
106
107
|
let todo = include.todo;
|
|
107
108
|
|
|
109
|
+
let Caller = include.Caller;
|
|
110
|
+
|
|
111
|
+
let asCaller = include.asCaller;
|
|
112
|
+
|
|
108
113
|
let thenEvents = include.thenEvents;
|
|
109
114
|
|
|
110
115
|
let thenNoEvent = include.thenNoEvent;
|
|
@@ -115,6 +120,8 @@ let thenEventsWithError = include.thenEventsWithError;
|
|
|
115
120
|
|
|
116
121
|
let thenError = include.thenError;
|
|
117
122
|
|
|
123
|
+
let thenRefused = include.thenRefused;
|
|
124
|
+
|
|
118
125
|
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
119
126
|
|
|
120
127
|
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
@@ -125,6 +132,8 @@ export {
|
|
|
125
132
|
todo,
|
|
126
133
|
test,
|
|
127
134
|
givenEvents,
|
|
135
|
+
Caller,
|
|
136
|
+
asCaller,
|
|
128
137
|
whenCmd,
|
|
129
138
|
thenEvent,
|
|
130
139
|
thenEvents,
|
|
@@ -132,6 +141,7 @@ export {
|
|
|
132
141
|
thenEventWithError,
|
|
133
142
|
thenEventsWithError,
|
|
134
143
|
thenError,
|
|
144
|
+
thenRefused,
|
|
135
145
|
thenAppendsConditionedOn,
|
|
136
146
|
thenAppendsConditionedOnExactly,
|
|
137
147
|
}
|
|
@@ -10,7 +10,8 @@ let include = Behavior_GWT$ReventlessGwt.Make({
|
|
|
10
10
|
consumedEventSchema: NotificationSourceClaims$OrderingPlugin.consumedEventSchema,
|
|
11
11
|
commandSchema: NotificationSourceClaims$OrderingPlugin.commandSchema,
|
|
12
12
|
errorSchema: NotificationSourceClaims$OrderingPlugin.errorSchema,
|
|
13
|
-
eventSchema: NotificationSourceClaims$OrderingPlugin.eventSchema
|
|
13
|
+
eventSchema: NotificationSourceClaims$OrderingPlugin.eventSchema,
|
|
14
|
+
commandAuthorization: NotificationSourceClaims$OrderingPlugin.commandAuthorization
|
|
14
15
|
})({
|
|
15
16
|
initialState: NotificationSourceClaims_Behavior$OrderingPlugin.initialState,
|
|
16
17
|
evolve: NotificationSourceClaims_Behavior$OrderingPlugin.evolve,
|
|
@@ -76,6 +77,10 @@ let Spec = include.Spec;
|
|
|
76
77
|
|
|
77
78
|
let todo = include.todo;
|
|
78
79
|
|
|
80
|
+
let Caller = include.Caller;
|
|
81
|
+
|
|
82
|
+
let asCaller = include.asCaller;
|
|
83
|
+
|
|
79
84
|
let thenEvents = include.thenEvents;
|
|
80
85
|
|
|
81
86
|
let thenEventWithError = include.thenEventWithError;
|
|
@@ -84,6 +89,8 @@ let thenEventsWithError = include.thenEventsWithError;
|
|
|
84
89
|
|
|
85
90
|
let thenError = include.thenError;
|
|
86
91
|
|
|
92
|
+
let thenRefused = include.thenRefused;
|
|
93
|
+
|
|
87
94
|
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
88
95
|
|
|
89
96
|
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
@@ -94,6 +101,8 @@ export {
|
|
|
94
101
|
todo,
|
|
95
102
|
test,
|
|
96
103
|
givenEvents,
|
|
104
|
+
Caller,
|
|
105
|
+
asCaller,
|
|
97
106
|
whenCmd,
|
|
98
107
|
thenEvent,
|
|
99
108
|
thenEvents,
|
|
@@ -101,6 +110,7 @@ export {
|
|
|
101
110
|
thenEventWithError,
|
|
102
111
|
thenEventsWithError,
|
|
103
112
|
thenError,
|
|
113
|
+
thenRefused,
|
|
104
114
|
thenAppendsConditionedOn,
|
|
105
115
|
thenAppendsConditionedOnExactly,
|
|
106
116
|
}
|
|
@@ -12,35 +12,35 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
12
12
|
|
|
13
13
|
// scenario-id: 44e2fd1b-d3da-4581-b102-0ccb47e004eb
|
|
14
14
|
test("placed order produces OrderCancelled with productIds carried over", () =>
|
|
15
|
-
givenEvents([OrderPlaced({productIds: [p1, p2]})])
|
|
15
|
+
givenEvents([OrderPlaced({productIds: [p1, p2], customerId: c1})])
|
|
16
16
|
->whenCmd(CancelOrder({orderId: o1}))
|
|
17
17
|
->thenEvent(OrderCancelled({orderId: o1, productIds: [p1, p2]}))
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
// scenario-id: 36e7a929-73a3-48ad-96bf-98265877dd9f
|
|
21
21
|
test("already cancelled order produces no events for CancelOrder (idempotent)", () =>
|
|
22
|
-
givenEvents([OrderPlaced({productIds: [p1]}), OrderCancelled])
|
|
22
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1}), OrderCancelled])
|
|
23
23
|
->whenCmd(CancelOrder({orderId: o1}))
|
|
24
24
|
->thenNoEvent
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
// scenario-id: a8adfaaf-2a97-487d-b80b-34b2e79a621d
|
|
28
28
|
test("shipped order returns OrderAlreadyShipped for CancelOrder", () =>
|
|
29
|
-
givenEvents([OrderPlaced({productIds: [p1]}), OrderShipped])
|
|
29
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1}), OrderShipped])
|
|
30
30
|
->whenCmd(CancelOrder({orderId: o1}))
|
|
31
31
|
->thenError(OrderAlreadyShipped)
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
// scenario-id: da5c2d1d-adaf-412c-ba71-293158b29841
|
|
35
35
|
test("ReopenOrder on cancelled order produces OrderReopened", () =>
|
|
36
|
-
givenEvents([OrderPlaced({productIds: [p1]}), OrderCancelled])
|
|
36
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1}), OrderCancelled])
|
|
37
37
|
->whenCmd(ReopenOrder({orderId: o1}))
|
|
38
38
|
->thenEvent(OrderReopened({orderId: o1}))
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
// scenario-id: edebec12-a5ec-4f71-a1fc-f1db65108db9
|
|
42
42
|
test("ReopenOrder on a placed order produces no events (idempotent)", () =>
|
|
43
|
-
givenEvents([OrderPlaced({productIds: [p1]})])
|
|
43
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
44
44
|
->whenCmd(ReopenOrder({orderId: o1}))
|
|
45
45
|
->thenNoEvent
|
|
46
46
|
)
|
|
@@ -50,7 +50,7 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
50
50
|
// shipped — the case no test covered, which is how it survived.
|
|
51
51
|
// scenario-id: 96bdee04-7518-4297-81f5-7242a0cffa9f
|
|
52
52
|
test("ReopenOrder on a shipped order returns OrderAlreadyShipped", () =>
|
|
53
|
-
givenEvents([OrderPlaced({productIds: [p1]}), OrderShipped])
|
|
53
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1}), OrderShipped])
|
|
54
54
|
->whenCmd(ReopenOrder({orderId: o1}))
|
|
55
55
|
->thenError(OrderAlreadyShipped)
|
|
56
56
|
)
|
|
@@ -61,4 +61,39 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
61
61
|
->whenCmd(ReopenOrder({orderId: o1}))
|
|
62
62
|
->thenError(OrderNotFound)
|
|
63
63
|
)
|
|
64
|
+
|
|
65
|
+
// Only the customer who placed an order may cancel it. The slice says so by
|
|
66
|
+
// marking `@owner` on the `customerId` its `OrderPlaced` carries; an operator
|
|
67
|
+
// still cancels on anyone's behalf.
|
|
68
|
+
// scenario-id: 80c0ad21-a352-43d6-862c-74c5250991d1
|
|
69
|
+
test("the customer who placed the order may cancel it", () =>
|
|
70
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
71
|
+
->asCaller(Caller.owner(c1))
|
|
72
|
+
->whenCmd(CancelOrder({orderId: o1}))
|
|
73
|
+
->thenEvent(OrderCancelled({orderId: o1, productIds: [p1]}))
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
// scenario-id: 48fc5fa8-449d-40df-b58d-e87f0acea478
|
|
77
|
+
test("another customer cannot cancel the order", () =>
|
|
78
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
79
|
+
->asCaller(Caller.owner(c2))
|
|
80
|
+
->whenCmd(CancelOrder({orderId: o1}))
|
|
81
|
+
->thenRefused
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
// scenario-id: e7561ebf-5566-4a4e-87c0-9aa403d68310
|
|
85
|
+
test("an operator may cancel any customer's order", () =>
|
|
86
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
87
|
+
->asCaller(Caller.operator)
|
|
88
|
+
->whenCmd(CancelOrder({orderId: o1}))
|
|
89
|
+
->thenEvent(OrderCancelled({orderId: o1, productIds: [p1]}))
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
// scenario-id: e0df85d2-f997-4833-816e-39ddce5c895e
|
|
93
|
+
test("a caller who is not signed in cannot cancel an order", () =>
|
|
94
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
95
|
+
->asCaller(Caller.anonymous)
|
|
96
|
+
->whenCmd(CancelOrder({orderId: o1}))
|
|
97
|
+
->thenRefused
|
|
98
|
+
)
|
|
64
99
|
})
|
|
@@ -10,7 +10,8 @@ let include = Behavior_GWT$ReventlessGwt.Make({
|
|
|
10
10
|
consumedEventSchema: CancelOrder$OrderingPlugin.consumedEventSchema,
|
|
11
11
|
commandSchema: CancelOrder$OrderingPlugin.commandSchema,
|
|
12
12
|
errorSchema: CancelOrder$OrderingPlugin.errorSchema,
|
|
13
|
-
eventSchema: CancelOrder$OrderingPlugin.eventSchema
|
|
13
|
+
eventSchema: CancelOrder$OrderingPlugin.eventSchema,
|
|
14
|
+
commandAuthorization: CancelOrder$OrderingPlugin.commandAuthorization
|
|
14
15
|
})({
|
|
15
16
|
initialState: CancelOrder_Behavior$OrderingPlugin.initialState,
|
|
16
17
|
evolve: CancelOrder_Behavior$OrderingPlugin.evolve,
|
|
@@ -23,6 +24,10 @@ let test = include.test;
|
|
|
23
24
|
|
|
24
25
|
let givenEvents = include.givenEvents;
|
|
25
26
|
|
|
27
|
+
let Caller = include.Caller;
|
|
28
|
+
|
|
29
|
+
let asCaller = include.asCaller;
|
|
30
|
+
|
|
26
31
|
let whenCmd = include.whenCmd;
|
|
27
32
|
|
|
28
33
|
let thenEvent = include.thenEvent;
|
|
@@ -31,6 +36,8 @@ let thenNoEvent = include.thenNoEvent;
|
|
|
31
36
|
|
|
32
37
|
let thenError = include.thenError;
|
|
33
38
|
|
|
39
|
+
let thenRefused = include.thenRefused;
|
|
40
|
+
|
|
34
41
|
describe("CancelOrder StateChangeSlice", () => {
|
|
35
42
|
test("non-existent order returns OrderNotFound for CancelOrder", () => thenError(whenCmd(givenEvents([]), {
|
|
36
43
|
TAG: "CancelOrder",
|
|
@@ -41,7 +48,8 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
41
48
|
productIds: [
|
|
42
49
|
Ordering_Examples$OrderingPlugin.p1,
|
|
43
50
|
Ordering_Examples$OrderingPlugin.p2
|
|
44
|
-
]
|
|
51
|
+
],
|
|
52
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
45
53
|
}]), {
|
|
46
54
|
TAG: "CancelOrder",
|
|
47
55
|
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
@@ -56,7 +64,8 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
56
64
|
test("already cancelled order produces no events for CancelOrder (idempotent)", () => thenNoEvent(whenCmd(givenEvents([
|
|
57
65
|
{
|
|
58
66
|
TAG: "OrderPlaced",
|
|
59
|
-
productIds: [Ordering_Examples$OrderingPlugin.p1]
|
|
67
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
68
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
60
69
|
},
|
|
61
70
|
"OrderCancelled"
|
|
62
71
|
]), {
|
|
@@ -66,7 +75,8 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
66
75
|
test("shipped order returns OrderAlreadyShipped for CancelOrder", () => thenError(whenCmd(givenEvents([
|
|
67
76
|
{
|
|
68
77
|
TAG: "OrderPlaced",
|
|
69
|
-
productIds: [Ordering_Examples$OrderingPlugin.p1]
|
|
78
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
79
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
70
80
|
},
|
|
71
81
|
"OrderShipped"
|
|
72
82
|
]), {
|
|
@@ -76,7 +86,8 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
76
86
|
test("ReopenOrder on cancelled order produces OrderReopened", () => thenEvent(whenCmd(givenEvents([
|
|
77
87
|
{
|
|
78
88
|
TAG: "OrderPlaced",
|
|
79
|
-
productIds: [Ordering_Examples$OrderingPlugin.p1]
|
|
89
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
90
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
80
91
|
},
|
|
81
92
|
"OrderCancelled"
|
|
82
93
|
]), {
|
|
@@ -88,7 +99,8 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
88
99
|
}));
|
|
89
100
|
test("ReopenOrder on a placed order produces no events (idempotent)", () => thenNoEvent(whenCmd(givenEvents([{
|
|
90
101
|
TAG: "OrderPlaced",
|
|
91
|
-
productIds: [Ordering_Examples$OrderingPlugin.p1]
|
|
102
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
103
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
92
104
|
}]), {
|
|
93
105
|
TAG: "ReopenOrder",
|
|
94
106
|
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
@@ -96,7 +108,8 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
96
108
|
test("ReopenOrder on a shipped order returns OrderAlreadyShipped", () => thenError(whenCmd(givenEvents([
|
|
97
109
|
{
|
|
98
110
|
TAG: "OrderPlaced",
|
|
99
|
-
productIds: [Ordering_Examples$OrderingPlugin.p1]
|
|
111
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
112
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
100
113
|
},
|
|
101
114
|
"OrderShipped"
|
|
102
115
|
]), {
|
|
@@ -107,6 +120,46 @@ describe("CancelOrder StateChangeSlice", () => {
|
|
|
107
120
|
TAG: "ReopenOrder",
|
|
108
121
|
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
109
122
|
}), "OrderNotFound"));
|
|
123
|
+
test("the customer who placed the order may cancel it", () => thenEvent(whenCmd(asCaller(givenEvents([{
|
|
124
|
+
TAG: "OrderPlaced",
|
|
125
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
126
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
127
|
+
}]), Caller.owner(Ordering_Examples$OrderingPlugin.c1, undefined)), {
|
|
128
|
+
TAG: "CancelOrder",
|
|
129
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
130
|
+
}), {
|
|
131
|
+
TAG: "OrderCancelled",
|
|
132
|
+
orderId: Ordering_Examples$OrderingPlugin.o1,
|
|
133
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1]
|
|
134
|
+
}));
|
|
135
|
+
test("another customer cannot cancel the order", () => thenRefused(whenCmd(asCaller(givenEvents([{
|
|
136
|
+
TAG: "OrderPlaced",
|
|
137
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
138
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
139
|
+
}]), Caller.owner(Ordering_Examples$OrderingPlugin.c2, undefined)), {
|
|
140
|
+
TAG: "CancelOrder",
|
|
141
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
142
|
+
})));
|
|
143
|
+
test("an operator may cancel any customer's order", () => thenEvent(whenCmd(asCaller(givenEvents([{
|
|
144
|
+
TAG: "OrderPlaced",
|
|
145
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
146
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
147
|
+
}]), Caller.operator), {
|
|
148
|
+
TAG: "CancelOrder",
|
|
149
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
150
|
+
}), {
|
|
151
|
+
TAG: "OrderCancelled",
|
|
152
|
+
orderId: Ordering_Examples$OrderingPlugin.o1,
|
|
153
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1]
|
|
154
|
+
}));
|
|
155
|
+
test("a caller who is not signed in cannot cancel an order", () => thenRefused(whenCmd(asCaller(givenEvents([{
|
|
156
|
+
TAG: "OrderPlaced",
|
|
157
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
158
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
159
|
+
}]), Caller.anonymous), {
|
|
160
|
+
TAG: "CancelOrder",
|
|
161
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
162
|
+
})));
|
|
110
163
|
});
|
|
111
164
|
|
|
112
165
|
let Spec = include.Spec;
|
|
@@ -129,6 +182,8 @@ export {
|
|
|
129
182
|
todo,
|
|
130
183
|
test,
|
|
131
184
|
givenEvents,
|
|
185
|
+
Caller,
|
|
186
|
+
asCaller,
|
|
132
187
|
whenCmd,
|
|
133
188
|
thenEvent,
|
|
134
189
|
thenEvents,
|
|
@@ -136,6 +191,7 @@ export {
|
|
|
136
191
|
thenEventWithError,
|
|
137
192
|
thenEventsWithError,
|
|
138
193
|
thenError,
|
|
194
|
+
thenRefused,
|
|
139
195
|
thenAppendsConditionedOn,
|
|
140
196
|
thenAppendsConditionedOnExactly,
|
|
141
197
|
}
|
|
@@ -14,7 +14,8 @@ let include = Behavior_GWT$ReventlessGwt.Make({
|
|
|
14
14
|
consumedEventSchema: PlaceOrder$OrderingPlugin.consumedEventSchema,
|
|
15
15
|
commandSchema: PlaceOrder$OrderingPlugin.commandSchema,
|
|
16
16
|
errorSchema: PlaceOrder$OrderingPlugin.errorSchema,
|
|
17
|
-
eventSchema: PlaceOrder$OrderingPlugin.eventSchema
|
|
17
|
+
eventSchema: PlaceOrder$OrderingPlugin.eventSchema,
|
|
18
|
+
commandAuthorization: PlaceOrder$OrderingPlugin.commandAuthorization
|
|
18
19
|
})({
|
|
19
20
|
initialState: PlaceOrder_Behavior$OrderingPlugin.initialState,
|
|
20
21
|
evolve: PlaceOrder_Behavior$OrderingPlugin.evolve,
|
|
@@ -814,6 +815,10 @@ let Spec = include.Spec;
|
|
|
814
815
|
|
|
815
816
|
let todo = include.todo;
|
|
816
817
|
|
|
818
|
+
let Caller = include.Caller;
|
|
819
|
+
|
|
820
|
+
let asCaller = include.asCaller;
|
|
821
|
+
|
|
817
822
|
let thenEvents = include.thenEvents;
|
|
818
823
|
|
|
819
824
|
let thenNoEvent = include.thenNoEvent;
|
|
@@ -822,6 +827,8 @@ let thenEventWithError = include.thenEventWithError;
|
|
|
822
827
|
|
|
823
828
|
let thenEventsWithError = include.thenEventsWithError;
|
|
824
829
|
|
|
830
|
+
let thenRefused = include.thenRefused;
|
|
831
|
+
|
|
825
832
|
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
826
833
|
|
|
827
834
|
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
@@ -832,6 +839,8 @@ export {
|
|
|
832
839
|
todo,
|
|
833
840
|
test,
|
|
834
841
|
givenEvents,
|
|
842
|
+
Caller,
|
|
843
|
+
asCaller,
|
|
835
844
|
whenCmd,
|
|
836
845
|
thenEvent,
|
|
837
846
|
thenEvents,
|
|
@@ -839,6 +848,7 @@ export {
|
|
|
839
848
|
thenEventWithError,
|
|
840
849
|
thenEventsWithError,
|
|
841
850
|
thenError,
|
|
851
|
+
thenRefused,
|
|
842
852
|
thenAppendsConditionedOn,
|
|
843
853
|
thenAppendsConditionedOnExactly,
|
|
844
854
|
}
|
|
@@ -43,3 +43,37 @@ describe("ShipOrder StateChangeSlice", () => {
|
|
|
43
43
|
->thenEvent(OrderShipped({orderId: o1, customerId: c1}))
|
|
44
44
|
)
|
|
45
45
|
})
|
|
46
|
+
|
|
47
|
+
describe("Who may ShipOrder", () => {
|
|
48
|
+
// scenario-id: a0ce6e35-29df-48c8-81d8-5af12a0f48d1
|
|
49
|
+
test("a Fulfilment may ship an order", () =>
|
|
50
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
51
|
+
->asCaller(Caller.inRoles([Fulfilment]))
|
|
52
|
+
->whenCmd(ShipOrder({orderId: o1}))
|
|
53
|
+
->thenEvent(OrderShipped({orderId: o1, customerId: c1}))
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
// scenario-id: 6af9d686-1310-43e5-946e-90ed1ec14d18
|
|
57
|
+
test("an Admin may ship an order", () =>
|
|
58
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
59
|
+
->asCaller(Caller.inRoles([Admin]))
|
|
60
|
+
->whenCmd(ShipOrder({orderId: o1}))
|
|
61
|
+
->thenEvent(OrderShipped({orderId: o1, customerId: c1}))
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
// scenario-id: 5b4f7a52-ec5e-4282-a7c8-a74432af13da
|
|
65
|
+
test("a shopper may not ship an order", () =>
|
|
66
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
67
|
+
->asCaller(Caller.owner(c1))
|
|
68
|
+
->whenCmd(ShipOrder({orderId: o1}))
|
|
69
|
+
->thenRefused
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
// scenario-id: 020c3695-3e3d-4343-8d38-d9d33ccf22f0
|
|
73
|
+
test("an anonymous caller may not ship an order", () =>
|
|
74
|
+
givenEvents([OrderPlaced({productIds: [p1], customerId: c1})])
|
|
75
|
+
->asCaller(Caller.anonymous)
|
|
76
|
+
->whenCmd(ShipOrder({orderId: o1}))
|
|
77
|
+
->thenRefused
|
|
78
|
+
)
|
|
79
|
+
})
|
|
@@ -10,7 +10,8 @@ let include = Behavior_GWT$ReventlessGwt.Make({
|
|
|
10
10
|
consumedEventSchema: ShipOrder$OrderingPlugin.consumedEventSchema,
|
|
11
11
|
commandSchema: ShipOrder$OrderingPlugin.commandSchema,
|
|
12
12
|
errorSchema: ShipOrder$OrderingPlugin.errorSchema,
|
|
13
|
-
eventSchema: ShipOrder$OrderingPlugin.eventSchema
|
|
13
|
+
eventSchema: ShipOrder$OrderingPlugin.eventSchema,
|
|
14
|
+
commandAuthorization: ShipOrder$OrderingPlugin.commandAuthorization
|
|
14
15
|
})({
|
|
15
16
|
initialState: ShipOrder_Behavior$OrderingPlugin.initialState,
|
|
16
17
|
evolve: ShipOrder_Behavior$OrderingPlugin.evolve,
|
|
@@ -23,6 +24,10 @@ let test = include.test;
|
|
|
23
24
|
|
|
24
25
|
let givenEvents = include.givenEvents;
|
|
25
26
|
|
|
27
|
+
let Caller = include.Caller;
|
|
28
|
+
|
|
29
|
+
let asCaller = include.asCaller;
|
|
30
|
+
|
|
26
31
|
let whenCmd = include.whenCmd;
|
|
27
32
|
|
|
28
33
|
let thenEvent = include.thenEvent;
|
|
@@ -31,6 +36,8 @@ let thenNoEvent = include.thenNoEvent;
|
|
|
31
36
|
|
|
32
37
|
let thenError = include.thenError;
|
|
33
38
|
|
|
39
|
+
let thenRefused = include.thenRefused;
|
|
40
|
+
|
|
34
41
|
describe("ShipOrder StateChangeSlice", () => {
|
|
35
42
|
test("non-existent order returns OrderNotFound", () => thenError(whenCmd(givenEvents([]), {
|
|
36
43
|
TAG: "ShipOrder",
|
|
@@ -88,6 +95,49 @@ describe("ShipOrder StateChangeSlice", () => {
|
|
|
88
95
|
}));
|
|
89
96
|
});
|
|
90
97
|
|
|
98
|
+
describe("Who may ShipOrder", () => {
|
|
99
|
+
test("a Fulfilment may ship an order", () => thenEvent(whenCmd(asCaller(givenEvents([{
|
|
100
|
+
TAG: "OrderPlaced",
|
|
101
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
102
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
103
|
+
}]), Caller.inRoles(["Fulfilment"])), {
|
|
104
|
+
TAG: "ShipOrder",
|
|
105
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
106
|
+
}), {
|
|
107
|
+
TAG: "OrderShipped",
|
|
108
|
+
orderId: Ordering_Examples$OrderingPlugin.o1,
|
|
109
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
110
|
+
}));
|
|
111
|
+
test("an Admin may ship an order", () => thenEvent(whenCmd(asCaller(givenEvents([{
|
|
112
|
+
TAG: "OrderPlaced",
|
|
113
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
114
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
115
|
+
}]), Caller.inRoles(["Admin"])), {
|
|
116
|
+
TAG: "ShipOrder",
|
|
117
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
118
|
+
}), {
|
|
119
|
+
TAG: "OrderShipped",
|
|
120
|
+
orderId: Ordering_Examples$OrderingPlugin.o1,
|
|
121
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
122
|
+
}));
|
|
123
|
+
test("a shopper may not ship an order", () => thenRefused(whenCmd(asCaller(givenEvents([{
|
|
124
|
+
TAG: "OrderPlaced",
|
|
125
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
126
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
127
|
+
}]), Caller.owner(Ordering_Examples$OrderingPlugin.c1, undefined)), {
|
|
128
|
+
TAG: "ShipOrder",
|
|
129
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
130
|
+
})));
|
|
131
|
+
test("an anonymous caller may not ship an order", () => thenRefused(whenCmd(asCaller(givenEvents([{
|
|
132
|
+
TAG: "OrderPlaced",
|
|
133
|
+
productIds: [Ordering_Examples$OrderingPlugin.p1],
|
|
134
|
+
customerId: Ordering_Examples$OrderingPlugin.c1
|
|
135
|
+
}]), Caller.anonymous), {
|
|
136
|
+
TAG: "ShipOrder",
|
|
137
|
+
orderId: Ordering_Examples$OrderingPlugin.o1
|
|
138
|
+
})));
|
|
139
|
+
});
|
|
140
|
+
|
|
91
141
|
let Spec = include.Spec;
|
|
92
142
|
|
|
93
143
|
let todo = include.todo;
|
|
@@ -108,6 +158,8 @@ export {
|
|
|
108
158
|
todo,
|
|
109
159
|
test,
|
|
110
160
|
givenEvents,
|
|
161
|
+
Caller,
|
|
162
|
+
asCaller,
|
|
111
163
|
whenCmd,
|
|
112
164
|
thenEvent,
|
|
113
165
|
thenEvents,
|
|
@@ -115,6 +167,7 @@ export {
|
|
|
115
167
|
thenEventWithError,
|
|
116
168
|
thenEventsWithError,
|
|
117
169
|
thenError,
|
|
170
|
+
thenRefused,
|
|
118
171
|
thenAppendsConditionedOn,
|
|
119
172
|
thenAppendsConditionedOnExactly,
|
|
120
173
|
}
|
|
@@ -4,6 +4,7 @@ let p1: CatalogSpec.ProductId.t = CatalogSpec.ProductId.makeFromString("p1")
|
|
|
4
4
|
let p2: CatalogSpec.ProductId.t = CatalogSpec.ProductId.makeFromString("p2")
|
|
5
5
|
|
|
6
6
|
let c1: CustomerId.t = CustomerId.makeFromString("c1")
|
|
7
|
+
let c2: CustomerId.t = CustomerId.makeFromString("c2")
|
|
7
8
|
let id: CustomerId.t = CustomerId.makeFromString("id")
|
|
8
9
|
|
|
9
10
|
let o1: OrderId.t = OrderId.makeFromString("o1")
|
|
@@ -11,6 +11,8 @@ let p2 = ProductId$CatalogSpec.makeFromString("p2");
|
|
|
11
11
|
|
|
12
12
|
let c1 = CustomerId$OrderingPlugin.makeFromString("c1");
|
|
13
13
|
|
|
14
|
+
let c2 = CustomerId$OrderingPlugin.makeFromString("c2");
|
|
15
|
+
|
|
14
16
|
let id = CustomerId$OrderingPlugin.makeFromString("id");
|
|
15
17
|
|
|
16
18
|
let o1 = OrderId$OrderingPlugin.makeFromString("o1");
|
|
@@ -71,6 +73,7 @@ export {
|
|
|
71
73
|
p1,
|
|
72
74
|
p2,
|
|
73
75
|
c1,
|
|
76
|
+
c2,
|
|
74
77
|
id,
|
|
75
78
|
o1,
|
|
76
79
|
o2,
|