Skip to content

Commit abea534

Browse files
authored
Merge pull request #289 from map-of-pi/dev
Automated PR to merge dev to main
2 parents 312edc1 + 4a2830e commit abea534

File tree

8 files changed

+279
-56
lines changed

8 files changed

+279
-56
lines changed

src/controllers/orderController.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,24 @@ export const getSingleOrder = async (req: Request, res: Response) => {
4848
}
4949
};
5050

51+
// TODO: To be removed once payment service is fully integrated
5152
export const createOrder = async (req: Request, res: Response) => {
52-
const { orderId, orderData, orderItems } = req.body;
53+
const buyer = req.currentUser as IUser;
54+
const { orderData, orderItems } = req.body;
5355
try {
54-
const updatedOrder = await orderService.createOrder(orderData, orderItems);
55-
return res.status(201).json(updatedOrder);
56+
// Ensure no payment ID is attached
57+
const sanitizedOrderData = { ...orderData, paymentId: null };
58+
const order = await orderService.createOrder(sanitizedOrderData, orderItems, buyer);
59+
if (!order) {
60+
logger.error(`Failed to create order with provided data: ${JSON.stringify(sanitizedOrderData)}`);
61+
return res.status(400).json({ message: "Invalid order data" });
62+
}
63+
64+
// Mark the order as paid (temporary behavior)
65+
const paidOrder = await orderService.markAsPaidOrder(order._id as string);
66+
return res.status(200).json(paidOrder);
5667
} catch (error) {
57-
logger.error(`Failed to create order for orderID ${ orderId }:`, error);
68+
logger.error(`Failed to create order:`, error);
5869
return res.status(500).json({
5970
message: 'An error occurred while creating order; please try again later'
6071
});

src/helpers/payment.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,13 @@ const checkoutProcess = async (
9696

9797
// Construct order data object
9898
const orderData = buildOrderData(
99-
buyer._id as string,
100-
seller._id as string,
99+
authUser.pi_uid as string,
100+
OrderPayment.seller as string,
101101
newPayment._id as string,
102102
currentPayment
103103
)
104104
// Create a new order along with its items
105-
const newOrder = await createOrder(orderData as NewOrder, OrderPayment.items);
105+
const newOrder = await createOrder(orderData as NewOrder, OrderPayment.items, authUser);
106106

107107
logger.info('order created successfully', { orderId: newOrder._id });
108108
return newOrder;

src/models/Order.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const orderSchema = new Schema<IOrder>(
88
{
99
payment_id: {
1010
type: SchemaTypes.ObjectId,
11-
required: true,
11+
required: false, // To change to true once payment integration is complete
1212
default: null,
1313
ref: "Payment",
1414
},

src/routes/order.routes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ orderRoutes.get("/:order_id", verifyToken, orderController.getSingleOrder);
169169
* 401:
170170
* description: Unauthorized
171171
* 400:
172-
* description: Bad request
172+
* description: Bad request | Invalid order data
173173
* 500:
174174
* description: Internal server error
175175
*/

src/services/order.service.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,32 @@ import SellerItem from "../models/SellerItem";
1111
import User from "../models/User";
1212
import { OrderStatusType } from "../models/enums/orderStatusType";
1313
import { OrderItemStatusType } from "../models/enums/orderItemStatusType";
14-
import { IOrder, NewOrder, PickedItems } from "../types";
14+
import { IOrder, IUser, NewOrder, PickedItems } from "../types";
1515
import logger from "../config/loggingConfig";
1616

1717
export const createOrder = async (
1818
orderData: NewOrder,
19-
orderItems: PickedItems[]
19+
orderItems: PickedItems[],
20+
authUser: IUser
2021
): Promise<IOrder> => {
2122
const session = await mongoose.startSession();
2223

2324
try {
2425
session.startTransaction();
2526

27+
// Look up the seller and buyer in the database
28+
const seller = await Seller.findOne({ seller_id: orderData.sellerId });
29+
const buyer = await User.findOne({ pi_uid: authUser?.pi_uid });
30+
31+
if (!buyer || !seller) {
32+
logger.error("Seller or buyer not found", { sellerId: orderData.sellerId, buyerId: authUser?.pi_uid });
33+
throw new Error("Seller or buyer not found");
34+
}
35+
2636
/* Step 1: Create a new Order record */
2737
const order = new Order({
28-
buyer_id: orderData.buyerId,
29-
seller_id: orderData.sellerId,
38+
buyer_id: buyer._id,
39+
seller_id: seller._id,
3040
payment_id: orderData.paymentId,
3141
total_amount: orderData.totalAmount,
3242
status: orderData.status,
@@ -128,6 +138,32 @@ export const updatePaidOrder = async (paymentId: string): Promise<IOrder> => {
128138
}
129139
};
130140

141+
// TODO: To be removed once payment service is fully integrated
142+
export const markAsPaidOrder = async (orderId: string): Promise<IOrder> => {
143+
try {
144+
const updatedOrder = await Order.findByIdAndUpdate(
145+
orderId,
146+
{
147+
$set: {
148+
is_paid: true,
149+
status: OrderStatusType.Pending
150+
}
151+
},
152+
{ new: true }
153+
).exec();
154+
155+
if (!updatedOrder) {
156+
logger.error(`Failed to update paid order for order ID ${ orderId }`);
157+
throw new Error('Failed to update paid order');
158+
}
159+
return updatedOrder;
160+
161+
} catch (error: any) {
162+
logger.error(`Failed to update paid order for order ${ orderId }: ${ error }`);
163+
throw error;
164+
}
165+
};
166+
131167
export const getSellerOrdersById = async (piUid: string) => {
132168
try {
133169
const seller = await Seller.exists({ seller_id: piUid });

test/controllers/orderController.spec.ts

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jest.mock('../../src/services/order.service', () => ({
2020
getOrderItems: jest.fn(),
2121
updateOrderStatus: jest.fn(),
2222
updateOrderItemStatus: jest.fn(),
23+
markAsPaidOrder: jest.fn()
2324
}));
2425

2526
describe('orderController', () => {
@@ -152,39 +153,68 @@ describe('orderController', () => {
152153

153154
describe('createOrder function', () => {
154155
const mockOrderId = '24f5a0f2a86d1f9f3b7e4e82';
156+
const mockUser = { pi_uid: '0a0a0a-0a0a-0a0a' };
157+
const mockOrderData = { payment_id: '0d367ba3a2e8438086c3ab7c0b7890c0' };
155158

156159
beforeEach(() => {
157160
req = {
158161
body: {
159-
orderId: mockOrderId,
160-
pi_username: 'testuser',
162+
orderData: mockOrderData,
161163
orderItems: [{ itemId: 'item-1' }],
162-
}
164+
},
165+
currentUser: mockUser
163166
};
164167
res = {
165168
status: jest.fn().mockReturnThis(),
166169
json: jest.fn(),
167170
};
168171
});
169172

170-
it('should return [201] and created/ updated order on success', async () => {
171-
const mockOrder = { id: mockOrderId, status: OrderStatusType.Initialized };
173+
it('should return [200] and created/ updated order on success', async () => {
174+
const mockOrder = { _id: mockOrderId, status: OrderStatusType.Initialized };
175+
const mockPaidOrder = { ...mockOrder, status: OrderStatusType.Pending };
172176
(orderService.createOrder as jest.Mock).mockResolvedValue(mockOrder);
177+
(orderService.markAsPaidOrder as jest.Mock).mockResolvedValue(mockPaidOrder);
173178

174179
await createOrder(req, res);
175180

176-
expect(orderService.createOrder).toHaveBeenCalledWith(req.body.orderData, req.body.orderItems);
177-
expect(res.status).toHaveBeenCalledWith(201);
178-
expect(res.json).toHaveBeenCalledWith(mockOrder);
181+
expect(orderService.createOrder).toHaveBeenCalledWith(
182+
{ ...mockOrderData, paymentId: null },
183+
req.body.orderItems,
184+
req.currentUser
185+
);
186+
expect(orderService.markAsPaidOrder).toHaveBeenCalledWith(mockOrderId);
187+
expect(res.status).toHaveBeenCalledWith(200);
188+
expect(res.json).toHaveBeenCalledWith(mockPaidOrder);
179189
});
180190

181-
it('should return [500] if order service throws error', async () => {
191+
it('should return [400] if createOrder service returns null', async () => {
192+
(orderService.createOrder as jest.Mock).mockResolvedValue(null);
193+
194+
await createOrder(req, res);
195+
196+
expect(orderService.createOrder).toHaveBeenCalledWith(
197+
{ ...mockOrderData, paymentId: null },
198+
req.body.orderItems,
199+
req.currentUser
200+
);
201+
expect(orderService.markAsPaidOrder).not.toHaveBeenCalled();
202+
expect(res.status).toHaveBeenCalledWith(400);
203+
expect(res.json).toHaveBeenCalledWith({ message: 'Invalid order data' });
204+
});
205+
206+
it('should return [500] if createOrder service throws error', async () => {
182207
const mockError = new Error('An error occurred while creating order; please try again later');
183208
(orderService.createOrder as jest.Mock).mockRejectedValue(mockError);
184209

185210
await createOrder(req, res);
186211

187-
expect(orderService.createOrder).toHaveBeenCalledWith(req.body.orderData, req.body.orderItems);
212+
expect(orderService.createOrder).toHaveBeenCalledWith(
213+
{ ...mockOrderData, paymentId: null },
214+
req.body.orderItems,
215+
req.currentUser
216+
);
217+
expect(orderService.markAsPaidOrder).not.toHaveBeenCalled();
188218
expect(res.status).toHaveBeenCalledWith(500);
189219
expect(res.json).toHaveBeenCalledWith({ message: mockError.message });
190220
});

test/helpers/payment.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ describe('processPaymentApproval function', () => {
316316
paymentType: PaymentType.BuyerCheckout
317317
});
318318
expect(createOrder).toHaveBeenCalledWith({
319-
buyerId: mockBuyer._id,
319+
buyerId: mockUser.pi_uid,
320320
sellerId: mockSeller._id,
321321
paymentId: mockPayment._id,
322322
totalAmount: mockPayment.amount,
@@ -325,7 +325,8 @@ describe('processPaymentApproval function', () => {
325325
sellerFulfillmentDescription: currentPayment.metadata.OrderPayment?.seller_fulfillment_description,
326326
buyerFulfillmentDescription: currentPayment.metadata.OrderPayment?.buyer_fulfillment_description,
327327
},
328-
currentPayment.metadata.OrderPayment?.items
328+
currentPayment.metadata.OrderPayment?.items,
329+
mockUser
329330
);
330331
expect(platformAPIClient.post).toHaveBeenCalledWith(`/v2/payments/${ mockPiPaymentId }/approve`);
331332
expect(result).toEqual({

0 commit comments

Comments
 (0)