Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev/ananya/point shop rework #273

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/common/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { MentorOfficeHours } from "../services/mentor/mentor-schemas";
import { Event, EventAttendance, EventFollowers } from "../services/event/event-schemas";
import { NewsletterSubscription } from "../services/newsletter/newsletter-schemas";
import { RegistrationApplication } from "../services/registration/registration-schemas";
import { ShopItem } from "../services/shop/shop-schemas";
import { ShopItem, ShopOrder } from "../services/shop/shop-schemas";
import { UserAttendance, UserFollowing, UserInfo } from "../services/user/user-schemas";
import { AnyParamConstructor, IModelOptions } from "@typegoose/typegoose/lib/types";
import { StaffShift } from "../services/staff/staff-schemas";
Expand Down Expand Up @@ -73,6 +73,7 @@ enum RegistrationCollection {

enum ShopCollection {
ITEMS = "items",
ORDERS = "orders"
}

enum StaffCollection {
Expand Down Expand Up @@ -152,6 +153,7 @@ export default class Models {

// Shop
static ShopItem: Model<ShopItem> = getModel(ShopItem, Group.SHOP, ShopCollection.ITEMS);
static ShopOrder: Model<ShopOrder> = getModel(ShopOrder, Group.SHOP, ShopCollection.ORDERS);

// Staff
static StaffShift: Model<StaffShift> = getModel(StaffShift, Group.STAFF, StaffCollection.SHIFT);
Expand Down
131 changes: 130 additions & 1 deletion src/services/shop/shop-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import {
ShopItemSchema,
ShopItemsSchema,
ShopItemUpdateRequestSchema,
ShopItemGenerateOrderSchema,
ShopItemFulfillOrderSchema,
SuccessSchema,
ShopOrder,
OrderQRCodesSchema,
} from "./shop-schemas";
import { Router } from "express";
import { StatusCode } from "status-code-enum";
Expand Down Expand Up @@ -188,7 +193,7 @@ shopRouter.get(
method: "get",
path: "/shop/item/qr/{id}/",
tag: Tag.SHOP,
role: Role.STAFF,
role: null, //Role.STAFF
summary: "Gets the QR codes for a shop item",
parameters: z.object({
id: ShopItemIdSchema,
Expand Down Expand Up @@ -218,6 +223,130 @@ shopRouter.get(
},
);


shopRouter.post(
"/item/generateorder",
specification({
method: "post",
path: "/shop/item/generateorder/",
tag: Tag.SHOP,
role: null,
summary: "Generates order and returns qr code",
body: ShopItemGenerateOrderSchema,
responses: {
[StatusCode.SuccessOK]: {
description: "The qr codes",
schema: OrderQRCodesSchema,
},
[StatusCode.ClientErrorNotFound]: {
description: "Item doesn't exist",
schema: ShopItemNotFoundErrorSchema,
},
[StatusCode.ClientErrorBadRequest]: {
description: "Not enough quantity in shop",
schema: ShopInsufficientFundsErrorSchema, //potentially change
},
},
}),
async (req, res) => {
const body = req.body;
const items = body.items;
const quantity = body.quantity


//const body = ShopItemGenerateOrderSchema.parse(req.body)
//const { items, quantity } = body;

for(let i = 0; i < items.length; i++) {
//items[i] is the _id of the items
const item = await Models.ShopItem.findOne({ itemId: items[i] });

if (!item) {
return res.status(StatusCode.ClientErrorNotFound).send(ShopItemNotFoundError);
}

const q = quantity?.[i] as number | undefined;
if(q == undefined || item.quantity < q) {
// send which item there isn't enough of ?
return res.status(StatusCode.ClientErrorNotFound).send(ShopInsufficientFundsError);
}
}

//have availability of all item so can generate qr code with order number
const RAND_NUM = 10;
const order = Math.floor(Math.random() * RAND_NUM);
const qrCodeUrl = `hackillinois://ordernum?orderNum=${order}`;

const shopOrder: ShopOrder = {
orderNum: order,
items: items,
quantity: quantity,
};

await Models.ShopOrder.create(shopOrder);

return res.status(StatusCode.SuccessOK).send({ qrInfo: qrCodeUrl });
},
);

shopRouter.post(
"/item/fulfillorder",
specification({
method: "post",
path: "/shop/item/fulfillorder/",
tag: Tag.SHOP,
role: null,
summary: "Purchases the order item",
body: ShopItemFulfillOrderSchema,
responses: {
[StatusCode.SuccessOK]: {
description: "The successfully purchased order",
schema: SuccessSchema,
},
[StatusCode.ClientErrorNotFound]: {
description: "Order doesn't exist",
schema: ShopItemNotFoundErrorSchema,
},
},
}),
async (req, res) => {
// when qr code is scanned, will call this so body needs to have order num and then i use that
// to get the order and then for each item in the order, subtract the quantity and then return success
const body = req.body;
const num = body.orderNum;

const order = await Models.ShopOrder.findOne({ orderNum: num });

if(!order) {
return res.status(StatusCode.ClientErrorNotFound).send(ShopItemNotFoundError);
}

for(let i = 0; i < order.items.length; i++) {
const item = await Models.ShopItem.findOne({ itemId: order.items[i] });

if(!item) {
return res.status(StatusCode.ClientErrorNotFound).send(ShopItemNotFoundError);
}

const q = order.quantity?.[i] as number | 0;

const updatedItem = await Models.ShopItem.findOneAndUpdate({ itemId: order.items[i] }, body, {
quantity: item.quantity - q,
});

if (!updatedItem) {
return res.status(StatusCode.ClientErrorNotFound).send(ShopItemNotFoundError);
}

//item.quantity = item.quantity - q;
//await item.save();
}

return res.status(StatusCode.SuccessOK).json({ message: "success" });
},
);


shopRouter.post(
"/item/buy",
specification({
Expand Down
50 changes: 50 additions & 0 deletions src/services/shop/shop-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,33 @@ export class ShopItem {
}
}

export class ShopOrder {
@prop({ required: true })
public orderNum: number
@prop({ required: true })
public items: Array<string>

@prop({ required: true })
public quantity: Array<number>

constructor(
orderNum: number,
items: Array<string>,
quantity: Array<number>,
) {
this.orderNum = orderNum;
this.items = items;
this.quantity = quantity;
}
}

export const ShopItemIdSchema = z.string().openapi("ShopItemId", { example: "item1234" });
// export const ShopOrderArraySchema = z
// .tuple([
// z.array(z.string()),
// z.array(z.number()),
// ])
// .openapi("ShopOrderArray", { example: [["item1234", "item5678"], [1, 2]] });

export const ShopItemSchema = z
.object({
Expand Down Expand Up @@ -112,6 +138,30 @@ export const ShopItemBuyRequestSchema = z.object({
instance: z.string().openapi({ example: "1x3" }),
});

// needs to have list of items and quantity
export const ShopItemGenerateOrderSchema = z.object({
items: z.array(z.string()),
quantity: z.array(z.number()),
});

export const ShopItemFulfillOrderSchema = z.object({
orderNum: z.number(),
});

export const OrderQRCodeSchema = z.string().openapi("OrderQRCode", {
example: "hackillinois://ordernum?orderNum=10",
});

export const OrderQRCodesSchema = z
.object({
qrInfo: z.string(OrderQRCodeSchema),
})
.openapi("OrderQRCodes");

export const SuccessSchema = z.object({
message: z.string(),
}).openapi("Success");

export const [ShopItemAlreadyExistsError, ShopItemAlreadyExistsErrorSchema] = CreateErrorAndSchema({
error: "AlreadyExists",
message: "An item with that id already exists, did you mean to update it instead?",
Expand Down
Loading