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

Fix/Product Category and Variant Relations #1332

Open
wants to merge 5 commits into
base: dev
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
59 changes: 46 additions & 13 deletions src/database/seeding/seeding.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,38 +226,71 @@ export class SeedingService {
await categoryRepository.save([c1, c2, c3]);

// Create products with associated categories
const category1 = await categoryRepository.findOne({
where: { name: 'electricity' },
});

if (!category1) {
throw new BadRequestException(`Invalid category: electricity`);
}

const p1 = productRepository.create({
name: 'Product 1',
description: 'Description for Product 1',
size: ProductSizeType.STANDARD,
category: 'electricity',
quantity: 1,
price: 500,
category: category1,
quantity: 2,
price: 50,
org: or1,
});
const category2 = await categoryRepository.findOne({
where: { name: 'electronics' },
});

if (!category2) {
throw new BadRequestException(`Invalid category: electronics`);
}

const p2 = productRepository.create({
name: 'Product 2',
description: 'Description for Product 2',
size: ProductSizeType.LARGE,
category: 'electricity',
quantity: 2,
price: 50,
size: ProductSizeType.STANDARD,
category: category2,
quantity: 5,
price: 100,
org: or2,
});

const category3 = await categoryRepository.findOne({
where: { name: 'electricity' },
});

if (!category3) {
throw new BadRequestException(`Invalid category: electricity`);
}

const p3 = productRepository.create({
name: 'Product 2',
description: 'Description for Product 2',
name: 'Product 3',
description: 'Description for Product 3',
size: ProductSizeType.STANDARD,
category: 'electricity',
category: category3,
quantity: 2,
price: 50,
org: or1,
});
const category4 = await categoryRepository.findOne({
where: { name: 'electricity' },
});

if (!category4) {
throw new BadRequestException(`Invalid category: electricity`);
}

const p4 = productRepository.create({
name: 'Product 2',
description: 'Description for Product 2',
name: 'Product 4',
description: 'Description for Product 4',
size: ProductSizeType.SMALL,
category: 'clothing',
category: category4,
quantity: 2,
price: 50,
org: or2,
Expand Down
2 changes: 1 addition & 1 deletion src/entities/base.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ export class AbstractBaseEntity {
@ApiProperty()
@UpdateDateColumn({ name: 'updated_at' })
updated_at: Date;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@
@ApiProperty()
@Column({ type: 'text', nullable: true })
description: string;

Check failure on line 15 in src/modules/product-category/entities/product-category.entity.ts

View workflow job for this annotation

GitHub Actions / lint-build-and-test

'OneToMany' is not defined

Check failure on line 15 in src/modules/product-category/entities/product-category.entity.ts

View workflow job for this annotation

GitHub Actions / lint-build-and-test

'Product' is not defined
@OneToMany(() => Product, product => product.category)

Check failure on line 16 in src/modules/product-category/entities/product-category.entity.ts

View workflow job for this annotation

GitHub Actions / lint-build-and-test

'Product' is not defined
products: Product[];
}
3 changes: 3 additions & 0 deletions src/modules/products/entities/product-variant.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ import { Product } from './product.entity';
export class ProductVariant {
@PrimaryGeneratedColumn('uuid')
id: string;

@ManyToOne(() => Product, product => product.variants, { onDelete: 'CASCADE' })
product: Product;
}
11 changes: 8 additions & 3 deletions src/modules/products/entities/product.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Comment } from '../../../modules/comments/entities/comments.entity';
import { Organisation } from '../../../modules/organisations/entities/organisations.entity';
import { Cart } from '../../dashboard/entities/cart.entity';
import { OrderItem } from '../../dashboard/entities/order-items.entity';
import { ProductVariant } from '../../products/entities/product-variant.entity';
import { ProductCategory } from '../../../modules/product-category/entities/product-category.entity';

export enum StockStatusType {
IN_STOCK = 'in stock',
Expand All @@ -25,9 +27,6 @@ export class Product extends AbstractBaseEntity {
@Column({ type: 'text', nullable: true })
description: string;

@Column({ type: 'text', nullable: true })
category: string;

@Column({ type: 'text', nullable: true })
image: string;

Expand Down Expand Up @@ -68,4 +67,10 @@ export class Product extends AbstractBaseEntity {

@OneToMany(() => Cart, cart => cart.product)
cart: Cart[];

@OneToMany(() => ProductVariant, variant => variant.product, { cascade: true })
variants?: ProductVariant[];

@ManyToOne(() => ProductCategory, category => category.products, { nullable: false })
category: ProductCategory; //category linked to the product
}
1 change: 1 addition & 0 deletions src/modules/products/products.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class ProductsController {
return await this.productsService.getTotalProducts();
}


@ApiBearerAuth()
@UseGuards(OwnershipGuard)
@Post('organisations/:orgId/products')
Expand Down
1 change: 1 addition & 0 deletions src/modules/products/products.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Product } from './entities/product.entity';
import { ProductsController } from './products.controller';
import { ProductsService } from './products.service';


@Module({
imports: [
TypeOrmModule.forFeature([
Expand Down
25 changes: 21 additions & 4 deletions src/modules/products/products.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BadRequestException,
ForbiddenException,
HttpStatus,
Injectable,
Expand All @@ -17,7 +18,6 @@
import { User } from '../user/entities/user.entity';
import { CreateProductRequestDto } from './dto/create-product.dto';
import { UpdateProductDTO } from './dto/update-product.dto';
import { ProductVariant } from './entities/product-variant.entity';
import { Product, ProductSizeType, StockStatusType } from './entities/product.entity';

interface SearchCriteria {
Expand All @@ -34,7 +34,8 @@
@InjectRepository(Product) private productRepository: Repository<Product>,
@InjectRepository(Organisation) private organisationRepository: Repository<Organisation>,
@InjectRepository(Comment) private commentRepository: Repository<Comment>,
@InjectRepository(User) private userRepository: Repository<User>
@InjectRepository(User) private userRepository: Repository<User>,
@InjectRepository(ProductCategory) private categoryRepository: Repository<ProductCategory>

Check failure on line 38 in src/modules/products/products.service.ts

View workflow job for this annotation

GitHub Actions / lint-build-and-test

'ProductCategory' is not defined

Check failure on line 38 in src/modules/products/products.service.ts

View workflow job for this annotation

GitHub Actions / lint-build-and-test

'ProductCategory' is not defined
) {}

async createProduct(id: string, dto: CreateProductRequestDto) {
Expand All @@ -55,18 +56,33 @@
size: dto.size as ProductSizeType,
};

const newProduct: Product = this.productRepository.create(payload);
const category = await this.categoryRepository.findOne({
where: { id: payload.category },
});

if (!category) {
throw new BadRequestException(`Invalid category ID: ${payload.category}`);
}

const newProduct: Product = this.productRepository.create({
...payload,
category,
});

newProduct.org = org;
const statusCal = await this.calculateProductStatus(dto.quantity);
newProduct.stock_status = statusCal;
newProduct.cost_price = 0.2 * dto.price - dto.price;

const product = await this.productRepository.save(newProduct);
if (!product || !newProduct)

if (!product || !newProduct) {
throw new InternalServerErrorException({
status_code: 500,
status: 'Internal server error',
message: 'An unexpected error occurred. Please try again later.',
});
}

return {
status: 'success',
Expand Down Expand Up @@ -198,6 +214,7 @@
try {
await this.productRepository.update(productId, {
...updateProductDto,
category: updateProductDto.category ? { id: updateProductDto.category } : undefined,
cost_price: 0.2 * updateProductDto.price - updateProductDto.price,
stock_status: await this.calculateProductStatus(updateProductDto.quantity),
});
Expand Down
3 changes: 2 additions & 1 deletion src/modules/products/tests/mocks/deleted-product.mock.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { randomUUID } from 'crypto';
import { orgMock } from '../../../organisations/tests/mocks/organisation.mock';
import { Product, StockStatusType } from '../../entities/product.entity';
import { productCategoryMock } from './product-category.mock';

enum ProductSizeType {
SMALL = 'Small',
Expand All @@ -15,7 +16,7 @@ export const deletedProductMock: Product = {
stock_status: StockStatusType.LOW_STOCK,
image: '',
price: 12,
category: 'Fashion',
category: productCategoryMock,
quantity: 7,
cost_price: 10,
orderItems: [],
Expand Down
11 changes: 11 additions & 0 deletions src/modules/products/tests/mocks/product-category.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ProductCategory } from "src/modules/product-category/entities/product-category.entity";


export const productCategoryMock: ProductCategory = {
id: 'category-id-123',
name: 'Fashion',
description: '',
products: [],
created_at: new Date(),
updated_at: new Date(),
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CreateProductRequestDto } from '../../dto/create-product.dto';
import { productMock } from './product.mock';


export const createProductRequestDtoMock: CreateProductRequestDto = {
name: productMock.name,
price: productMock.price,
Expand Down
4 changes: 3 additions & 1 deletion src/modules/products/tests/mocks/product.mock.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { randomUUID } from 'crypto';
import { orgMock } from '../../../../modules/organisations/tests/mocks/organisation.mock';
import { Product, StockStatusType } from '../../entities/product.entity';
import { productCategoryMock } from './product-category.mock';


enum ProductSizeType {
SMALL = 'Small',
Expand All @@ -15,7 +17,7 @@ export const productMock: Product = {
stock_status: StockStatusType.LOW_STOCK,
image: '',
price: 12,
category: 'Fashion',
category: productCategoryMock,
quantity: 7,
size: ProductSizeType.SMALL,
org: orgMock,
Expand Down
Loading