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

Fixes #120

Merged
merged 59 commits into from
Aug 26, 2024
Merged

Fixes #120

Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
f9108f8
rebase
AimePazzo Jun 1, 2024
56c3ce6
Merge pull request #44 from atlp-rwanda/ft-admin
AimePazzo Jun 1, 2024
281b3b8
rebase
AimePazzo Jun 1, 2024
8a315e8
Merge pull request #45 from atlp-rwanda/ft-admin
AimePazzo Jun 1, 2024
9c65028
Ft login v google 187584916 (#47)
Jadowacu1 Jun 4, 2024
5a3356d
Logout feature (#26) (#46)
MANISHIMWESalton Jun 4, 2024
dad2ece
[Finishes #187584924] Seller Create/Add a product (#48)
AimePazzo Jun 6, 2024
dac5a4c
Logout feature (#26)
solangeihirwe03 May 31, 2024
91a286e
Fixed login fetaure (#59)
ProgrammerDATCH Jun 7, 2024
96e83ed
Ft delete items seller #187584926 (#52)
solangeihirwe03 Jun 7, 2024
8ae4ea1
[starts #187584911] Seller statistics per timeframe (#54)
ProgrammerDATCH Jun 8, 2024
5978342
Ft update password 187584920 (#56)
hbapte Jun 9, 2024
73bae0f
Ft seller available products 187584925 (#49)
SaddockAime Jun 9, 2024
99c7974
Ft seller update items 187584929 (#51)
Fabrice-Dush Jun 10, 2024
d82b834
Ft 2 fa v2 187584919 (#60)
Y-elv Jun 10, 2024
041ed3d
The Seller and User - list products (#58)
ndahimana154 Jun 11, 2024
50ad8dc
Ft buyer view cart 187584934 (#64)
ProgrammerDATCH Jun 13, 2024
1b2c1d9
User Search Products by FIlters (#65)
ndahimana154 Jun 16, 2024
5a60d80
ft-view-specific-item (#63)
Jadowacu1 Jun 17, 2024
e0f43f5
[starts #187584933] Add & Update cart (#70)
ProgrammerDATCH Jun 18, 2024
6982bda
Users should be able to chat on the App to ask some information publi…
AimePazzo Jun 18, 2024
939338e
User Search Products by FIlters (#65) (#71)
Jadowacu1 Jun 18, 2024
0c3479a
ft clear wishList (#75)
Jadowacu1 Jun 19, 2024
b1fa94d
adding cron job to products (#76)
Y-elv Jun 20, 2024
41b358f
Ft buyer clear cart 187584935 (#66)
Fabrice-Dush Jun 20, 2024
5863c70
ft buyer view products from wishList (#79)
Jadowacu1 Jun 21, 2024
a6cdec4
ft: password-expiry-check-#187584942 (#72)
hbapte Jun 22, 2024
86c3302
[Delivers-18758493] ft-buyer-checkout (#77)
MANISHIMWESalton Jun 22, 2024
987c6bf
Fixed calculation of cart (#80)
ProgrammerDATCH Jun 23, 2024
dc27e45
[Deliver-18758493] ft-fix-checkout (#82)
MANISHIMWESalton Jun 24, 2024
563cd8a
[Fixes #187584929] (#84)
Fabrice-Dush Jun 25, 2024
1de31f6
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
AimePazzo Jun 26, 2024
bdb7c02
[Delivers #187584943] ft-notifications (#68)
SaddockAime Jun 26, 2024
f370e49
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
AimePazzo Jun 26, 2024
0496ccb
Ft mark one or all notification as read (#69)
SaddockAime Jun 26, 2024
5a71f0f
merged
AimePazzo Jun 26, 2024
f1bb7f1
Ft add product reviews #187584931 (#73)
solangeihirwe03 Jun 27, 2024
6ab42d3
[Delivers #187584943] ft-notifications (#68) (#85)
Jadowacu1 Jul 1, 2024
853bef4
[Delivers-18758498] ft-buyer-stripe-payment (#78)
MANISHIMWESalton Jul 2, 2024
bb06e4b
fx-product-seeders (#88)
SaddockAime Jul 8, 2024
6ce7a6e
Ft submit seller request 187904713 (#87)
hbapte Jul 9, 2024
74b0c1e
Fix product response (#91)
ProgrammerDATCH Jul 11, 2024
7ca7d44
Fx notification route (#93)
SaddockAime Jul 12, 2024
4e31410
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
AimePazzo Jul 3, 2024
512a554
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Jul 12, 2024
5b3a076
fix password expiry check (#92)
hbapte Jul 12, 2024
fd0ff22
Fix passsword expiration check for google login accounts (#95)
hbapte Jul 16, 2024
938c14d
Fix codebase structure (#90)
ndahimana154 Jul 16, 2024
eb92726
Ft buyer track order status #187584937 (#74)
solangeihirwe03 Jul 16, 2024
925bc91
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Jul 18, 2024
580814e
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 4, 2024
0869546
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 5, 2024
4756042
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 5, 2024
5428ed3
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 5, 2024
1026490
Merge branch 'fixes' of github.com:atlp-rwanda/e-commerce-ninjas-bn i…
Aime-Patrick Aug 5, 2024
67f0888
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 5, 2024
4e58074
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 9, 2024
aa86fd2
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 19, 2024
4817a27
Merge branch 'develop' of github.com:atlp-rwanda/e-commerce-ninjas-bn…
Aime-Patrick Aug 23, 2024
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
Prev Previous commit
Next Next commit
adding cron job to products (#76)
* ft clear wishList (#75)

* adding cron job to products

* adding cron job to products

* adding cron job to products

* resolving conflicts

---------

Co-authored-by: Niyonshuti Jean De Dieu <152473876+Jadowacu1@users.noreply.github.com>
Y-elv and Jadowacu1 authored Jun 20, 2024
commit b1fa94d24592ed1b6abbb14befba8b2422e79afd
40 changes: 20 additions & 20 deletions src/databases/seeders/20240520202759-users.ts
Original file line number Diff line number Diff line change
@@ -31,8 +31,8 @@ const userOne = {
role: "admin",
status: "enabled",
isVerified: true,
is2FAEnabled: false
}
is2FAEnabled: false,
};
const userTwo = {
id: userTwoId,
createdAt: new Date(),
@@ -50,8 +50,8 @@ const userTwo = {
role: "buyer",
status: "enabled",
isVerified: true,
is2FAEnabled: false
}
is2FAEnabled: false,
};

const userThree = {
id: userThreeId,
@@ -70,8 +70,8 @@ const userThree = {
role: "buyer",
status: "enabled",
isVerified: true,
is2FAEnabled: true
}
is2FAEnabled: true,
};

const userFour = {
id: userFourId,
@@ -90,8 +90,8 @@ const userFour = {
role: "seller",
status: "enabled",
isVerified: true,
is2FAEnabled: false
}
is2FAEnabled: false,
};

const userFive = {
id: userFiveId,
@@ -110,7 +110,7 @@ const userFive = {
role: "seller",
status: "enabled",
isVerified: true,
is2FAEnabled: false
is2FAEnabled: false,
};

const userSix = {
@@ -130,7 +130,7 @@ const userSix = {
role: "seller",
status: "enabled",
isVerified: true,
is2FAEnabled: false
is2FAEnabled: false,
};

const userSeven = {
@@ -150,7 +150,7 @@ const userSeven = {
role: "seller",
status: "enabled",
isVerified: true,
is2FAEnabled: false
is2FAEnabled: false,
};

const userEight = {
@@ -170,8 +170,8 @@ const userEight = {
role: "buyer",
status: "enabled",
isVerified: true,
is2FAEnabled: false
}
is2FAEnabled: false,
};
const userNine = {
id: userNineId,
createdAt: new Date(),
@@ -189,8 +189,8 @@ const userNine = {
role: "nurse",
status: "enabled",
isVerified: true,
is2FAEnabled: false
}
is2FAEnabled: false,
};

const userTen = {
id: userTenId,
@@ -209,12 +209,12 @@ const userTen = {
role: "buyer",
status: "enabled",
isVerified: true,
is2FAEnabled: false
}
is2FAEnabled: false,
};

export const up = (queryInterface: QueryInterface) =>
queryInterface.bulkInsert("users", [
userOne,
userOne,
userTwo,
userThree,
userFour,
@@ -223,9 +223,9 @@ export const up = (queryInterface: QueryInterface) =>
userSeven,
userEight,
userNine,
userTen
userTen,
]);

export const down = async (queryInterface: QueryInterface) => {
await queryInterface.bulkDelete("users", {});
};
};
9 changes: 6 additions & 3 deletions src/databases/seeders/20240601224835-products.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,8 @@ const productOne = {
id: productOneId,
shopId: shopOneId,
name: "Lotion",
description: "Our luxurious lotion store, offering a curated selection of nourishing formulas designed to hydrate and pamper. From silky-smooth textures to delightful fragrances, experience the ultimate in skincare indulgence at our boutique",
description:
"Our luxurious lotion store, offering a curated selection of nourishing formulas designed to hydrate and pamper. From silky-smooth textures to delightful fragrances, experience the ultimate in skincare indulgence at our boutique",
price: 19.99,
discount: "10%",
category: "Cosmetics",
@@ -30,7 +31,8 @@ const productTwo = {
id: productTwoId,
shopId: shopTwoId,
name: "Pizza",
description: "Our authentic pizza store, where each slice is crafted with love and tradition. From classic Margherita to adventurous toppings, indulge in a culinary journey that delights the senses.",
description:
"Our authentic pizza store, where each slice is crafted with love and tradition. From classic Margherita to adventurous toppings, indulge in a culinary journey that delights the senses.",
price: 19.99,
discount: "10%",
category: "Food",
@@ -48,7 +50,8 @@ const productThree = {
id: productThreeId,
shopId: shopTwoId,
name: "Fanta",
description: "Our Fanta store, where fizzy refreshment meets bold fruit sensations. From tangy orange to exotic tropical blends, quench your thirst with our vibrant array of sodas.",
description:
"Our Fanta store, where fizzy refreshment meets bold fruit sensations. From tangy orange to exotic tropical blends, quench your thirst with our vibrant array of sodas.",
price: 19.99,
discount: "10%",
category: "Drinks",
71 changes: 71 additions & 0 deletions src/helpers/updateExpiredProducts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Product from "../databases/models/products";
import { Op } from "sequelize";
import { sendEmail } from "../services/sendEmail";
import Shop from "../databases/models/shops";
import User from "../databases/models/users";

const updateExpiredProducts = async () => {
try {
const expiredProducts = await Product.findAll({
where: {
expiryDate: { [Op.lt]: new Date() },
expired: false
},
attributes: ["id", "shopId", "name"]
});

for (const product of expiredProducts) {
await product.update({
expired: true,
status: "unavailable"
});
}

const shopIds = expiredProducts.map((product) => product.shopId);
const shops = await Shop.findAll({
where: {
id: {
[Op.in]: shopIds
}
},
attributes: ["id", "userId"]
});

const userIds = shops.map((shop) => shop.userId);

const users = await User.findAll({
where: {
id: {
[Op.in]: userIds
}
},
attributes: ["id", "email", "firstName"]
});

const userMap = {};
users.forEach((user) => {
userMap[user.id] = {
email: user.email,
firstName: user.firstName
};
});

for (const product of expiredProducts) {
const UserShop = shops.find((shop) => shop.id === product.shopId);
if (UserShop) {
const user = userMap[UserShop.userId];
if (user) {
await sendEmail(
user.email,
"Product Expired",
`Dear ${user.firstName}, your product ${product.name} has expired and now is unavailable.`
);
}
}
}
} catch (error) {
console.error("Error updating expired products:", error.message);
}
};

export default updateExpiredProducts;
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import httpStatus from "http-status";
import chat from "./services/chat";
import { createServer } from "http";
import { Server } from "socket.io";
import "./services/cronJob"

dotenv.config();

@@ -38,6 +39,8 @@ app.get("**", (req: Request, res: Response) => {
message: "Welcome to the e-Commerce Ninjas BackEnd."
});
});


server.listen(PORT, () => {
console.log(`Server is running on the port ${PORT}`);
});
80 changes: 80 additions & 0 deletions src/modules/product/test/product.spec.ts
Original file line number Diff line number Diff line change
@@ -16,6 +16,11 @@ import userRepositories from "../../user/repository/userRepositories";
import userControllers from "../../user/controller/userControllers";
import authRepositories from "../../auth/repository/authRepositories";
import { ExtendRequest } from "../../../types";
import Product from "../../../databases/models/products";
import Shop from "../../../databases/models/shops";
import User from "../../../databases/models/users";
import { sendEmail, transporter } from "../../../services/sendEmail";
import updateExpiredProducts from "../../../helpers/updateExpiredProducts";

chai.use(chaiHttp);
const router = () => chai.request(app);
@@ -1176,4 +1181,79 @@ describe("Wishlist Routes", () => {
expect(res.json.calledWith({ message: "Internal server error", error: errorMessage })).to.be.true;
});
});
});

describe("updateExpiredProducts", () => {
let req: Partial<Request>;
let res: Partial<Response>;
let productFindAllStub: sinon.SinonStub;
let productUpdateStub: sinon.SinonStub;
let shopFindAllStub: sinon.SinonStub;
let userFindAllStub: sinon.SinonStub;

beforeEach(() => {
req = {};
res = {
status: sinon.stub().returnsThis(),
json: sinon.stub().returnsThis()
};

productFindAllStub = sinon.stub(Product, "findAll");
productUpdateStub = sinon.stub();
shopFindAllStub = sinon.stub(Shop, "findAll");
userFindAllStub = sinon.stub(User, "findAll");

Product.prototype.update = productUpdateStub;
});

afterEach(() => {
sinon.restore();
});

it("should update expired products and send emails to the respective users", async () => {
const expiredProducts = [
{
id: "productId1",
shopId: "shopId1",
name: "Product1",
update: productUpdateStub
},
{
id: "productId2",
shopId: "shopId2",
name: "Product2",
update: productUpdateStub
}
];

const shops = [
{ id: "shopId1", userId: "userId1" },
{ id: "shopId2", userId: "userId2" }
];

const users = [
{ id: "userId1", email: "user1@example.com", firstName: "User1" },
{ id: "userId2", email: "user2@example.com", firstName: "User2" }
];

productFindAllStub.onFirstCall().resolves(expiredProducts);
shopFindAllStub.resolves(shops);
userFindAllStub.resolves(users);

await updateExpiredProducts();

expect(productFindAllStub).to.have.been.calledOnce;
expect(productUpdateStub).to.have.been.calledTwice;
expect(shopFindAllStub).to.have.been.calledOnce;
expect(userFindAllStub).to.have.been.calledOnce;
expect(res.status).not.to.have.been.called;
expect(res.json).not.to.have.been.called;
});

it("should return 500 if an error occurs", async () => {
productFindAllStub.rejects(new Error("Internal Server Error"));

await updateExpiredProducts();
expect(productFindAllStub).to.have.been.calledOnce;
});
});
15 changes: 15 additions & 0 deletions src/services/cronJob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import cron from "node-cron";
import updateExpiredProducts from "../helpers/updateExpiredProducts";

cron.schedule(
"0 6 * * *",
async () => {
try {
console.log("Cron Job Started..");
await updateExpiredProducts();
} catch (error) {
console.error(`Something wrong occured " ${error.toString()} "`);
}
},
{ scheduled: true, timezone: "Asia/Kolkata" }
);