Skip to content

Commit 226e8fc

Browse files
committed
Added endpoints for removing product item and confirming shopping cart
1 parent b92d1ca commit 226e8fc

File tree

5 files changed

+114
-57
lines changed

5 files changed

+114
-57
lines changed

samples/unwrapping_onion/src/ecommerce/controllers/shoppingCartController.ts

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ import OpenShoppingCart from '../domain/commands/shoppingCarts/openShoppingCart'
55
import { mongoObjectId } from '#core/mongodb';
66
import { QueryBus } from '#core/queries';
77
import GetShoppingCartById from '../domain/queries/getShoppingCartById';
8-
import { assertNotEmptyString } from '#core/validation';
9-
import { AddProductItemRequest } from '../requests/shoppingCarts/addProductItemRequest';
8+
import { assertNotEmptyString, assertPositiveNumber } from '#core/validation';
9+
import { AddProductItemToShoppingCartRequest } from '../requests/shoppingCarts/addProductItemToShoppingCartRequest';
10+
import AddProductItemToShoppingCart from '../domain/commands/shoppingCarts/addProductItemToShoppingCart';
11+
import { ProductItem } from '../models/shoppingCarts/productItem';
12+
import RemoveProductItemFromShoppingCart from '../domain/commands/shoppingCarts/removeProductItemFromShoppingCart';
13+
import { RemoveProductItemFromShoppingCartRequest } from '../requests/shoppingCarts/removeProductItemFromShoppingCartRequest.ts';
14+
import ConfirmShoppingCart from '../domain/commands/shoppingCarts/confirmShoppingCart';
1015

1116
class ShoppingCartController {
1217
public router = Router();
@@ -18,9 +23,17 @@ class ShoppingCartController {
1823
'/:clientId/shopping-carts/:shoppingCartId/product-items',
1924
this.addProductItem
2025
);
26+
this.router.delete(
27+
'/:clientId/shopping-carts/:shoppingCartId/product-items',
28+
this.removeProductItem
29+
);
30+
this.router.post(
31+
'/:clientId/shopping-carts/:shoppingCartId/confirm',
32+
this.confirm
33+
);
2134
}
2235

23-
public open = async (
36+
private open = async (
2437
request: Request,
2538
response: Response,
2639
next: NextFunction
@@ -39,26 +52,69 @@ class ShoppingCartController {
3952
}
4053
};
4154

42-
public addProductItem = async (
43-
request: AddProductItemRequest,
55+
private addProductItem = async (
56+
request: AddProductItemToShoppingCartRequest,
4457
response: Response,
4558
next: NextFunction
4659
) => {
4760
try {
48-
const command = new OpenShoppingCart(
49-
mongoObjectId(),
50-
assertNotEmptyString(request.params.clientId)
61+
const command = new AddProductItemToShoppingCart(
62+
assertNotEmptyString(request.params.shoppingCartId),
63+
new ProductItem(
64+
assertNotEmptyString(request.body.productId),
65+
assertPositiveNumber(request.body.quantity)
66+
)
5167
);
5268
await this.commandBus.send(command);
5369

54-
sendCreated(response, command.shoppingCartId);
70+
response.sendStatus(200);
71+
} catch (error) {
72+
console.error(error);
73+
next(error);
74+
}
75+
};
76+
77+
private removeProductItem = async (
78+
request: RemoveProductItemFromShoppingCartRequest,
79+
response: Response,
80+
next: NextFunction
81+
) => {
82+
try {
83+
const command = new RemoveProductItemFromShoppingCart(
84+
assertNotEmptyString(request.params.shoppingCartId),
85+
new ProductItem(
86+
assertNotEmptyString(request.query.productId),
87+
assertPositiveNumber(request.query.quantity)
88+
)
89+
);
90+
await this.commandBus.send(command);
91+
92+
response.sendStatus(200);
93+
} catch (error) {
94+
console.error(error);
95+
next(error);
96+
}
97+
};
98+
99+
private confirm = async (
100+
request: Request,
101+
response: Response,
102+
next: NextFunction
103+
) => {
104+
try {
105+
const command = new ConfirmShoppingCart(
106+
assertNotEmptyString(request.params.shoppingCartId)
107+
);
108+
await this.commandBus.send(command);
109+
110+
response.sendStatus(200);
55111
} catch (error) {
56112
console.error(error);
57113
next(error);
58114
}
59115
};
60116

61-
public getById = async (
117+
private getById = async (
62118
request: Request,
63119
response: Response,
64120
next: NextFunction

samples/unwrapping_onion/src/ecommerce/requests/shoppingCarts/addProductItemRequest.ts renamed to samples/unwrapping_onion/src/ecommerce/requests/shoppingCarts/addProductItemToShoppingCartRequest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Request } from 'express';
22

3-
export type AddProductItemRequest = Request<
3+
export type AddProductItemToShoppingCartRequest = Request<
44
Partial<{ shoppingCartId: string }>,
55
unknown,
66
Partial<{ productId: number; quantity: number }>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Request } from 'express';
2+
3+
export type RemoveProductItemFromShoppingCartRequest = Request<
4+
Partial<{ shoppingCartId: string }>,
5+
unknown,
6+
unknown,
7+
Partial<{ productId: number; quantity: number }>
8+
>;

samples/unwrapping_onion/src/tests/e2e/fullFlow.e2e.test.ts

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -79,52 +79,41 @@ describe('Full flow', () => {
7979
revision: 1,
8080
});
8181
expect(response.body).toHaveProperty('openedAt');
82-
// current = response.body;
82+
//current = response.body;
8383

84-
// ///////////////////////////////////////////////////
85-
// // 2. Add product item
86-
// ///////////////////////////////////////////////////
87-
// const twoPairsOfShoes = {
88-
// quantity: 2,
89-
// productId: 123,
90-
// };
91-
// response = await request(app)
92-
// .post(`/v2/shopping-carts/${shoppingCartId}/product-items`)
93-
// .set('If-Match', currentRevision)
94-
// .send(twoPairsOfShoes)
95-
// .expect(200);
84+
///////////////////////////////////////////////////
85+
// 2. Add product item
86+
///////////////////////////////////////////////////
87+
const twoPairsOfShoes = {
88+
quantity: 2,
89+
productId: '123',
90+
};
91+
response = await request(app)
92+
.post(`/${clientId}/shopping-carts/${shoppingCartId}/product-items`)
93+
//.set('If-Match', currentRevision)
94+
.send(twoPairsOfShoes)
95+
.expect(200);
9696

9797
// expect(response.headers['etag']).toBeDefined();
9898
// expect(response.headers['etag']).toMatch(/W\/"\d+.*"/);
9999
// currentRevision = response.headers['etag'];
100100

101-
// response = await request(app)
102-
// .get(`/v2/shopping-carts/${shoppingCartId}`)
103-
// .set('If-Not-Match', lastRevision)
104-
// .expect(200);
101+
response = await request(app)
102+
.get(`/${clientId}/shopping-carts/${shoppingCartId}`)
103+
//.set('If-Not-Match', lastRevision)
104+
.expect(200);
105105

106106
// expect(response.headers['etag']).toBe(currentRevision);
107107
// lastRevision = response.headers['etag'];
108108

109-
// expect(response.body).toMatchObject({
110-
// id: current.id,
111-
// createdAt: current.createdAt,
112-
// sessionId: shoppingCartId,
113-
// city: null,
114-
// content: null,
115-
// country: null,
116-
// email: null,
117-
// firstName: null,
118-
// items: [twoPairsOfShoes],
119-
// lastName: null,
120-
// line1: null,
121-
// line2: null,
122-
// middleName: null,
123-
// mobile: null,
124-
// province: null,
125-
// userId: null,
126-
// status: ShoppingCartStatus.Opened,
127-
// });
109+
expect(response.body).toMatchObject({
110+
_id: shoppingCartId,
111+
clientId,
112+
status: ShoppingCartStatus.Opened,
113+
productItems: [twoPairsOfShoes],
114+
confirmedAt: null,
115+
revision: 1,
116+
});
128117
// expect(response.body.updatedAt).not.toBeNull();
129118
// current = response.body;
130119

@@ -136,7 +125,7 @@ describe('Full flow', () => {
136125
// quantity: 1,
137126
// };
138127
// response = await request(app)
139-
// .post(`/v2/shopping-carts/${shoppingCartId}/product-items`)
128+
// .post(`/${clientId}/shopping-carts/${shoppingCartId}/product-items`)
140129
// .set('If-Match', currentRevision)
141130
// .send(tShirt)
142131
// .expect(200);
@@ -146,7 +135,7 @@ describe('Full flow', () => {
146135
// currentRevision = response.headers['etag'];
147136

148137
// response = await request(app)
149-
// .get(`/v2/shopping-carts/${shoppingCartId}`)
138+
// .get(`/${clientId}/shopping-carts/${shoppingCartId}`)
150139
// .set('If-Not-Match', lastRevision)
151140
// .expect(200);
152141

@@ -186,7 +175,7 @@ describe('Full flow', () => {
186175
// };
187176
// response = await request(app)
188177
// .delete(
189-
// `/v2/shopping-carts/${shoppingCartId}/product-items?productId=${pairOfShoes.productId}&quantity=${pairOfShoes.quantity}`
178+
// `/shopping-carts/${shoppingCartId}/product-items?productId=${pairOfShoes.productId}&quantity=${pairOfShoes.quantity}`
190179
// )
191180
// .set('If-Match', currentRevision)
192181
// .expect(200);
@@ -196,7 +185,7 @@ describe('Full flow', () => {
196185
// currentRevision = response.headers['etag'];
197186

198187
// response = await request(app)
199-
// .get(`/v2/shopping-carts/${shoppingCartId}`)
188+
// .get(`/${clientId}/shopping-carts/${shoppingCartId}`)
200189
// .set('If-Not-Match', lastRevision)
201190
// .expect(200);
202191

@@ -238,7 +227,7 @@ describe('Full flow', () => {
238227
// };
239228

240229
// response = await request(app)
241-
// .put(`/v2/users/${userId}/shopping-carts/${shoppingCartId}`)
230+
// .put(`/users/${userId}/shopping-carts/${shoppingCartId}`)
242231
// .set('If-Match', currentRevision)
243232
// .send(confirmedData)
244233
// .expect(200);
@@ -248,7 +237,7 @@ describe('Full flow', () => {
248237
// currentRevision = response.headers['etag'];
249238

250239
// response = await request(app)
251-
// .get(`/v2/shopping-carts/${shoppingCartId}`)
240+
// .get(`/${clientId}/shopping-carts/${shoppingCartId}`)
252241
// .set('If-Not-Match', lastRevision)
253242
// .expect(200);
254243

@@ -269,7 +258,7 @@ describe('Full flow', () => {
269258
// current = response.body;
270259

271260
// // response = await request(app)
272-
// // .get(`/shopping-carts/${shoppingCartId}`)
261+
// // .get(`/${clientId}/shopping-carts/${shoppingCartId}`)
273262
// // .expect(200);
274263

275264
// // const { updatedAt, ...currentWithoutUpdatedAt } = current;
@@ -286,15 +275,15 @@ describe('Full flow', () => {
286275
// // // 4. Try to add product item
287276
// // // It should fail, as cart is already confirmed
288277
// // await request(app)
289-
// // .post(`/shopping-carts/${shoppingCartId}`)
278+
// // .post(`/${clientId}/shopping-carts/${shoppingCartId}`)
290279
// // .send({
291280
// // ...current,
292281
// // items: [twoPairsOfShoes, tShirt],
293282
// // })
294283
// // .expect(412);
295284

296285
// // response = await request(app)
297-
// // .get(`/shopping-carts/${shoppingCartId}`)
286+
// // .get(`/${clientId}/shopping-carts/${shoppingCartId}`)
298287
// // .expect(200);
299288

300289
// // expect(response.body).toMatchObject(current);

samples/unwrapping_onion/tsconfig.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,9 @@
7474
"skipLibCheck": true /* Skip type checking of declaration files. */,
7575
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
7676
},
77-
"include": ["./src/**/*", "./config.ts"]
77+
"include": [
78+
"./src/**/*",
79+
"./config.ts",
80+
"src/ecommerce/requests/shoppingCarts/removeProductItemFromShoppingCartRequest.ts.ts"
81+
]
7882
}

0 commit comments

Comments
 (0)