Skip to content

Commit

Permalink
Seller can be able to make product available or unavailable based on …
Browse files Browse the repository at this point in the history
…expired date or shortage of product in stock
  • Loading branch information
amin-leon committed May 8, 2024
1 parent 608d497 commit a3c1d03
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 1 deletion.
91 changes: 91 additions & 0 deletions src/controllers/productsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import uploadImage from '../helpers/claudinary';
import { sendInternalErrorResponse } from '../validations';
import { Product, ProductAttributes } from '../database/models/Product';
import { Size, SizeAttributes } from '../database/models/Size';
import { error } from 'console';
import logger from '../logs/config';

export const createProduct = async (req: Request, res: Response) => {
try {
Expand Down Expand Up @@ -69,3 +71,92 @@ export const createSize = async (req: Request, res: Response) => {
sendInternalErrorResponse(res, error);
}
};

// markProductsUnavailable
export const markProductAsUnavailable = async (req: Request, res: Response) => {
try {
const { sizeId } = req.params;

// find if given size exist
const sizeExist: any = await Size.findByPk(sizeId);

if (!sizeExist) {
res.status(404).json({
ok: false,
message: 'This size is not available',
});
}

// check if size has corresponding product
const product = await Product.findByPk(sizeExist?.productId);

if (!product) {
res.status(404).json({
ok: false,
message: 'This Product does not exist',
});
}

// update unavailability of product if expired date is less than current date or quantity<=0
if (sizeExist?.expiryDate <= new Date() || sizeExist?.quantity <= 0) {
await Size.update({ available: false }, { where: { id: sizeId } });

res.status(200).json({
status: 'OK',
message: 'This Product is successfully marked as unavailable',
});
} else {
res.status(403).json({
ok: false,
message: 'This Product already exist in stock with valid expiration date',
});
}
} catch (error) {
sendInternalErrorResponse(res, error);
logger.error(error);
}
};

export const markProductAsAvailable = async (req: Request, res: Response) => {
try {
const { sizeId } = req.params;

// find if given size exist
const sizeExist: any = await Size.findByPk(sizeId);

if (!sizeExist) {
res.status(404).json({
ok: false,
message: 'This size is not available',
});
}

// check if size has corresponding product
const product = await Product.findByPk(sizeExist?.productId);

if (!product) {
res.status(404).json({
ok: false,
message: 'This Product does not exist',
});
}

// update unavailability of product if expired date is less than current date or quantity<=0
if (sizeExist?.expiryDate > new Date() && sizeExist?.quantity >= 1) {
await Size.update({ available: true }, { where: { id: sizeId } });

res.status(200).json({
ok: true,
message: 'This Product is successfully marked as available',
});
} else {
res.status(403).json({
ok: false,
message: 'Check This Product in stock for its quantity and expired date',
});
}
} catch (error) {
sendInternalErrorResponse(res, error);
logger.error(error);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('sizes', 'available', {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: true,
});
},

async down(queryInterface, Sequelize) {
await queryInterface.removeColumn('sizes', 'available');
},
};
7 changes: 7 additions & 0 deletions src/database/models/Size.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface SizeAttributes {
discount?: number;
expiryDate?: Date;
productId: string;
available?: boolean;
}

export interface SizeCreationAttributes extends Optional<SizeAttributes, 'id'> {}
Expand All @@ -21,6 +22,7 @@ export class Size extends Model<SizeAttributes, SizeCreationAttributes> implemen
public discount!: number;
public expiryDate!: Date;
public productId!: string;
public available!: boolean;
}

Size.init(
Expand Down Expand Up @@ -62,6 +64,11 @@ Size.init(
onUpdate: 'CASCADE',
allowNull: false,
},
available: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true, // Set default value to true
},
},
{
sequelize,
Expand Down
112 changes: 112 additions & 0 deletions src/docs/products.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ tags:
paths:
/api/{categoryId}/products:
post:
security:
- bearerAuth: []
summary: Create a new product
tags:
- Product
Expand Down Expand Up @@ -99,7 +101,117 @@ paths:
message:
type: string
example: Something went wrong when creating the product

/api/products/{sizeId}/available:
put:
security:
- bearerAuth: []
summary: Mark a product as available in stock
tags:
- Product
description: |
This endpoint marks a product for a given sizeId as available.
parameters:
- name: sizeId
in: path
description: ID of the size to mark
required: true
type: string
responses:
200:
description: Product marked as available successfully
schema:
type: object
properties:
ok:
type: boolean
example: true
message:
type: string
example: This product is successfully marked as available
403:
description: Message response when the product cannot be marked as available
schema:
type: object
properties:
ok:
type: boolean
example: false
message:
type: string
example: Check this product in stock for its quantity and expiration date
404:
description: Message when the size or product is not found
schema:
type: object
properties:
ok:
type: boolean
example: false
message:
type: string
example: This size is not available
500:
description: Internal server error

/api/products/{sizeId}/unavailable:
put:
security:
- bearerAuth: []
summary: Mark a product as unavailable in stock
tags:
- Product
description: |
This endpoint marks a product for a given sizeId as unavailable when there is low stock or expired date is up.
parameters:
- name: sizeId
in: path
description: ID of the size to mark
required: true
type: string
responses:
200:
description: Product marked as unavailable in stock successfully
schema:
type: object
properties:
ok:
type: boolean
example: true
message:
type: string
example: This product is successfully marked as unavailable
403:
description: Message response when the product cannot be marked as unavailable
schema:
type: object
properties:
ok:
type: boolean
example: false
message:
type: string
example: This Product already exist in stock with valid expiration date
404:
description: Message when the size or product is not found
schema:
type: object
properties:
ok:
type: boolean
example: false
message:
type: string
example: This size is not available
500:
description: Internal server error

components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
Product:
type: object
Expand Down
9 changes: 8 additions & 1 deletion src/routes/productRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
import express from 'express';
import { createProduct, createSize } from '../controllers/productsController';
import {
createProduct,
createSize,
markProductAsAvailable,
markProductAsUnavailable,
} from '../controllers/productsController';
import multerUpload from '../helpers/multer';
import { checkUserRoles, isAuthenticated } from '../middlewares/authMiddlewares';

Expand All @@ -15,3 +20,5 @@ productRouter.post(
);

productRouter.post('/:productId/add-size', isAuthenticated, checkUserRoles('seller'), createSize);
productRouter.put('/:sizeId/available', isAuthenticated, checkUserRoles('seller'), markProductAsAvailable);
productRouter.put('/:sizeId/unavailable', isAuthenticated, checkUserRoles('seller'), markProductAsUnavailable);

0 comments on commit a3c1d03

Please sign in to comment.