Skip to content

Online Shopping - Revamp Seller Item Registration #226

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

Merged
merged 12 commits into from
Mar 8, 2025
Merged
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
608 changes: 295 additions & 313 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
},
"dependencies": {
"@sentry/integrations": "^7.114.0",
"@sentry/node": "^9.3.0",
"@sentry/profiling-node": "^9.3.0",
"@sentry/node": "^8.26.0",
"@sentry/profiling-node": "^8.26.0",
"axios": "^1.7.4",
"body-parser": "^1.20.2",
"bottleneck": "^2.19.5",
"cloudinary": "^2.4.0",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"express": "^4.21.2",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.9.5",
"multer": "^1.4.5-lts.1",
Expand Down
11 changes: 3 additions & 8 deletions src/models/SellerItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,13 @@ const sellerItemSchema = new Schema<ISellerItem>(
default: 1,
min: 1
},
created_at: {
type: Date,
required: true,
},
updated_at: {
type: Date,
required: true,
},
expired_by: {
type: Date,
required: true,
}
},
{
timestamps: true, // Enables createdAt and updatedAt
}
);

Expand Down
14 changes: 7 additions & 7 deletions src/models/enums/stockLevelType.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export enum StockLevelType {
available_1 = '1 available',
available_2 = '2 available',
available_3 = '3 available',
many = 'Many available',
made_to_order = 'Made to order',
ongoing_service = 'Ongoing service',
sold = 'Sold'
AVAILABLE_1 = '1 available',
AVAILABLE_2 = '2 available',
AVAILABLE_3 = '3 available',
MANY_AVAILABLE = 'Many available',
MADE_TO_ORDER = 'Made to order',
ONGOING_SERVICE = 'Ongoing service',
SOLD = 'Sold'
}
17 changes: 7 additions & 10 deletions src/services/seller.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import mongoose from 'mongoose';
import Seller from "../models/Seller";
import User from "../models/User";
import UserSettings from "../models/UserSettings";
import SellerItem from "../models/SellerItem";
import { FulfillmentType, VisibleSellerType } from '../models/enums/sellerType';
import { StockLevelType } from '../models/enums/stockLevelType';
import { TrustMeterScale } from "../models/enums/trustMeterScale";
import { getUserSettingsById } from "./userSettings.service";
import { IUser, IUserSettings, ISeller, ISellerWithSettings, ISellerItem, ISanctionedRegion } from "../types";

import logger from "../config/loggingConfig";
import SellerItem from "../models/SellerItem";

// Helper function to get settings for all sellers and merge them into seller objects
const resolveSellerSettings = async (sellers: ISeller[]): Promise<ISellerWithSettings[]> => {
Expand Down Expand Up @@ -226,16 +227,15 @@ export const addOrUpdateSellerItem = async (
seller: ISeller,
item: ISellerItem
): Promise<ISellerItem | null> => {

try {
const today = new Date();

// Calculate expiration date based on duration (defaults to 1 week)
// Ensure duration is valid (default to 1 week)
const duration = Number(item.duration) || 1;
const durationInMs = duration * 7 * 24 * 60 * 60 * 1000;
const expiredBy = new Date(today.getTime() + durationInMs);

// Ensure unique identifier is used for finding existing items
// Define a unique query for finding existing items
const query = {
_id: item._id || undefined,
seller_id: seller.seller_id,
Expand All @@ -248,7 +248,6 @@ export const addOrUpdateSellerItem = async (
// Update the existing item
existingItem.set({
...item,
updated_at: today,
expired_by: expiredBy,
image: item.image || existingItem.image, // Use existing image if a new one isn't provided
});
Expand All @@ -257,7 +256,7 @@ export const addOrUpdateSellerItem = async (
logger.info('Item updated successfully:', { updatedItem });
return updatedItem;
} else {
// Ensure item has a unique identifier for creation
// Create a new item with a unique ID
const newItemId = item._id || new mongoose.Types.ObjectId().toString();

// Create a new item
Expand All @@ -267,11 +266,9 @@ export const addOrUpdateSellerItem = async (
name: item.name ? item.name.trim() : '',
description: item.description ? item.description.trim() : '',
price: parseFloat(item.price?.toString() || '0.01'), // Ensure valid price
stock_level: item.stock_level || '1 available',
stock_level: item.stock_level || StockLevelType.AVAILABLE_1,
duration: parseInt(item.duration?.toString() || '1'), // Ensure valid duration
image: item.image,
created_at: today,
updated_at: today,
expired_by: expiredBy,
});

Expand All @@ -281,7 +278,7 @@ export const addOrUpdateSellerItem = async (
return newItem;
}
} catch (error) {
logger.error(`Failed to add or update seller item for sellerID ${ seller.seller_id }:`, error);
logger.error(`Failed to add or update seller item for sellerID ${seller.seller_id}:`, error);
throw new Error('Failed to add or update seller item; please try again later');
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@
stock_level: StockLevelType;
image?: string;
duration: number;
created_at: Date;
updated_at: Date;
expired_by: Date;
createdAt: Date;
updatedAt: Date;
}
export interface IReviewFeedback extends Document {
_id: string;
Expand Down
24 changes: 12 additions & 12 deletions test/mockData.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@
"stock_level": "1 available",
"image": "http://example.com/testSellerOneItemOne.jpg",
"duration": 1,
"created_at": "2025-01-08T00:00:00.000Z",
"updated_at": "2025-01-08T00:00:00.000Z",
"expired_by": "2025-01-15T00:00:00.000Z"
"expired_by": "2025-01-15T00:00:00.000Z",
"createdAt": "2025-01-08T00:00:00.000Z",
"updatedAt": "2025-01-08T00:00:00.000Z"
},
{
"_id": "24f5a0f2a86d1f9f3b7e4e82",
Expand All @@ -237,9 +237,9 @@
"stock_level": "2 available",
"image": "http://example.com/testSellerOneItemTwo.jpg",
"duration": 2,
"created_at": "2025-01-08T00:00:00.000Z",
"updated_at": "2025-01-08T00:00:00.000Z",
"expired_by": "2025-01-22T00:00:00.000Z"
"expired_by": "2025-01-22T00:00:00.000Z",
"createdAt": "2025-01-08T00:00:00.000Z",
"updatedAt": "2025-01-08T00:00:00.000Z"
},
{
"_id": "25f5a0f2a86d1f9f3b7e4e81",
Expand All @@ -250,9 +250,9 @@
"stock_level": "Sold",
"image": "http://example.com/testSellerTwoItemOne.jpg",
"duration": 1,
"created_at": "2025-01-09T00:00:00.000Z",
"updated_at": "2025-01-09T00:00:00.000Z",
"expired_by": "2025-01-16T00:00:00.000Z"
"expired_by": "2025-01-16T00:00:00.000Z",
"createdAt": "2025-01-09T00:00:00.000Z",
"updatedAt": "2025-01-09T00:00:00.000Z"
},
{
"_id": "25f5a0f2a86d1f9f3b7e4e82",
Expand All @@ -263,9 +263,9 @@
"stock_level": "Ongoing service",
"image": "http://example.com/testSellerTwoItemTwo.jpg",
"duration": 1,
"created_at": "2025-01-10T00:00:00.000Z",
"updated_at": "2025-01-10T00:00:00.000Z",
"expired_by": "2025-01-17T00:00:00.000Z"
"expired_by": "2025-01-17T00:00:00.000Z",
"createdAt": "2025-01-10T00:00:00.000Z",
"updatedAt": "2025-01-10T00:00:00.000Z"
}
],
"reviews": [
Expand Down
43 changes: 22 additions & 21 deletions test/services/seller.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,14 @@ describe('addOrUpdateSellerItem function', () => {
plainObject.price = Number(plainObject.price);
}

if (plainObject.created_at) {
plainObject.created_at = new Date(plainObject.created_at);
plainObject.created_at.setHours(0, 0, 0, 0);
if (plainObject.createdAt) {
plainObject.createdAt = new Date(plainObject.createdAt);
plainObject.createdAt.setHours(0, 0, 0, 0);
}

if (plainObject.updated_at) {
plainObject.updated_at = new Date(plainObject.updated_at);
plainObject.updated_at.setHours(0, 0, 0, 0);
if (plainObject.updatedAt) {
plainObject.updatedAt = new Date(plainObject.updatedAt);
plainObject.updatedAt.setHours(0, 0, 0, 0);
}

if (plainObject.expired_by) {
Expand All @@ -262,7 +262,7 @@ describe('addOrUpdateSellerItem function', () => {
};

const assertUpdatedSellerItem = (actual: any, expected: any) => {
const { __v, created_at, ...filteredActual } = actual; // ignore DB values.
const { __v, createdAt, ...filteredActual } = actual; // ignore DB values.
expect(filteredActual).toEqual(expect.objectContaining({ ...expected, _id: actual._id }));
};

Expand All @@ -274,7 +274,8 @@ describe('addOrUpdateSellerItem function', () => {
price: 0.50,
stock_level: "Many available",
duration: 2,
image: 'http://example.com/testSellerThreeItemOne.jpg'
image: 'http://example.com/testSellerThreeItemOne.jpg',
createdAt: '2025-02-20T00:00:00.000Z'
} as unknown as ISellerItem;

const sellerItemData = (await addOrUpdateSellerItem(
Expand All @@ -300,9 +301,9 @@ describe('addOrUpdateSellerItem function', () => {
stock_level: sellerItem.stock_level,
duration: sellerItem.duration,
image: sellerItem.image,
created_at: current_date,
updated_at: current_date,
expired_by: expired_date
expired_by: expired_date,
createdAt: current_date,
updatedAt: current_date
});
});

Expand Down Expand Up @@ -343,8 +344,8 @@ describe('addOrUpdateSellerItem function', () => {
stock_level: sellerItem.stock_level,
duration: sellerItem.duration,
image: sellerItem.image,
updated_at: current_date,
expired_by: expired_date
expired_by: expired_date,
updatedAt: current_date
});
});

Expand Down Expand Up @@ -381,11 +382,11 @@ describe('deleteSellerItem function', () => {
}

// Normalize timestamps
if (plainObject.created_at instanceof Date) {
plainObject.created_at = plainObject.created_at.toISOString();
if (plainObject.createdAt instanceof Date) {
plainObject.createdAt = plainObject.createdAt.toISOString();
}
if (plainObject.updated_at instanceof Date) {
plainObject.updated_at = plainObject.updated_at.toISOString();
if (plainObject.updatedAt instanceof Date) {
plainObject.updatedAt = plainObject.updatedAt.toISOString();
}
if (plainObject.expired_by instanceof Date) {
plainObject.expired_by = plainObject.expired_by.toISOString();
Expand All @@ -409,8 +410,8 @@ describe('deleteSellerItem function', () => {
stock_level: "Ongoing service",
duration: 1,
image: 'http://example.com/testSellerTwoItemTwo.jpg',
created_at: '2025-01-10T00:00:00.000Z',
updated_at: '2025-01-10T00:00:00.000Z',
createdAt: '2025-01-10T00:00:00.000Z',
updatedAt: '2025-01-10T00:00:00.000Z',
expired_by: '2025-01-17T00:00:00.000Z'
} as unknown as ISellerItem;

Expand All @@ -429,8 +430,8 @@ describe('deleteSellerItem function', () => {
stock_level: sellerItem.stock_level,
duration: sellerItem.duration,
image: sellerItem.image,
created_at: sellerItem.created_at,
updated_at: sellerItem.updated_at,
createdAt: sellerItem.createdAt,
updatedAt: sellerItem.updatedAt,
expired_by: sellerItem.expired_by
});
});
Expand Down