Commit 7d5875e5 authored by Gustavo Amaro da Silva's avatar Gustavo Amaro da Silva Committed by Lucas Gomes Martins
Browse files

hefesto/feature/endpoint listagem produto contratante

parent 55f34f2f
Showing with 154 additions and 23 deletions
+154 -23
export interface AuthenticatedRequest {
user: {
sub: number;
email: string;
};
}
import { Injectable, NotFoundException } from '@nestjs/common';
import {
ForbiddenException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ILike, IsNull, MoreThan, Repository } from 'typeorm';
import { CreateProductDto } from '../dto/createProductDto';
import { ProductEntity } from '../product.entity';
......@@ -9,7 +13,7 @@ export class ProductsService {
constructor(
@InjectRepository(ProductEntity)
private readonly productRepository: Repository<ProductEntity>,
) {}
) { }
async findAll(): Promise<ProductEntity[]> {
return await this.productRepository.find();
......@@ -25,28 +29,37 @@ export class ProductsService {
return product;
}
async create(product: CreateProductDto): Promise<ProductEntity> {
const newProduct = this.productRepository.create(product);
async create(
product: CreateProductDto,
company_id: number,
): Promise<ProductEntity> {
const newProduct = this.productRepository.create({
...product,
company: { id: company_id },
});
return await this.productRepository.save(newProduct);
}
async update(
id: number,
updateDto: CreateProductDto,
company_id: number,
): Promise<ProductEntity> {
const entity = await this.productRepository.findOne({ where: { id } });
const entity = await this.productRepository.findOne({
where: { id },
relations: { company: true },
});
if (!entity) {
throw new NotFoundException(`Product with ID ${id} not found`);
}
await this.productRepository.update(id, updateDto);
const updatedEntity = await this.productRepository.findOne({
where: { id },
});
if (entity.company.id !== company_id) {
throw new ForbiddenException();
}
return updatedEntity;
await this.productRepository.update(id, updateDto);
return this.productRepository.findOne({ where: { id } });
}
async delete(id: number): Promise<ProductEntity> {
......@@ -57,4 +70,67 @@ export class ProductsService {
product.deletedAt = new Date(Date.now());
return await this.productRepository.save(product);
}
async findAllActiveByCompany(companyId: number): Promise<any[]> {
const currentDate = new Date();
const threeDaysAhead = new Date(
currentDate.getTime() + 3 * 24 * 60 * 60 * 1000,
);
const products = await this.productRepository.find({
where: {
company: { id: companyId },
deletedAt: null,
expiration_date: MoreThan(threeDaysAhead),
},
});
return products.map((product) => ({
picture: product.picture,
name: product.name,
description: product.description,
quantity: product.quantity,
price: this.calculateDynamicPrice(product, currentDate),
brand: product.brand,
category: product.category,
expirationDate: product.expiration_date,
}));
}
async findByName(companyId: number, name: string): Promise<ProductEntity[]> {
const products = await this.productRepository.findBy({
name: ILike(`%${name}%`),
deletedAt: IsNull(),
company: { id: companyId },
});
if (!products) {
throw new NotFoundException(`Product with name ${name} not found`);
}
return products;
}
private calculateDynamicPrice(product: any, currentDate: Date): number {
const expirationDate = new Date(product.expiration_date);
const daysToExpiration = Math.ceil(
(expirationDate.getTime() - currentDate.getTime()) / (1000 * 3600 * 24),
);
if (daysToExpiration <= 3) {
product.price = 0; // gratis pra ongs
} else if (daysToExpiration <= 13) {
const initialPrice = product.price;
const daysOfDiscount = daysToExpiration - 2;
const maxDiscountDays = 10;
const priceReductionFactor = (maxDiscountDays - daysOfDiscount + 1) * 0.1;
product.price = Math.max(
0,
initialPrice - initialPrice * priceReductionFactor,
);
}
return product.price;
}
}
......@@ -14,10 +14,6 @@ export class CreateProductDto {
'ID da empresa (temporario; será determinado pela empresa autenticada)',
required: true,
})
@IsNotEmpty({ message: 'Empresa nao pode ser vazia' })
@IsNumber()
company: number;
@ApiProperty({
example: 'Banana',
description: 'nome do produto',
......
......@@ -6,7 +6,7 @@ import { ContractorCompaniesEntity } from '../contractorCompanies/contractorComp
export class ProductEntity extends BaseEntity {
@ManyToOne(() => ContractorCompaniesEntity)
@JoinColumn()
company: number;
company: ContractorCompaniesEntity;
@Column({ type: 'varchar', length: 255, nullable: false })
name: string;
......
......@@ -4,11 +4,12 @@ import {
Delete,
Get,
HttpException,
HttpStatus,
Param,
Post,
UseGuards,
Put,
HttpStatus,
Request,
} from '@nestjs/common';
import {
ApiBearerAuth,
......@@ -20,11 +21,49 @@ import {
import { ProductsService } from './domain/products.service';
import { CreateProductDto } from './dto/createProductDto';
import { AuthGuard } from '../auth/auth.guard';
import { AuthenticatedRequest } from '../auth/request';
@ApiTags('Produtos')
@Controller('products')
export class ProductsController {
constructor(private readonly productService: ProductsService) {}
constructor(private readonly productService: ProductsService) { }
@Get('/mine')
@ApiOperation({ summary: 'Listagem de produtos por empresa' })
@UseGuards(AuthGuard)
@ApiResponse({
status: 200,
description: 'Produtos da empresa encontrados',
type: Array<CreateProductDto>,
})
@ApiBearerAuth()
async getList(
@Request() req: AuthenticatedRequest,
): Promise<CreateProductDto[]> {
return this.productService.findAllActiveByCompany(req.user.sub);
}
@ApiOperation({ summary: 'Filtra os produtos da empresa por nome' })
@ApiParam({
name: 'name',
type: String,
required: true,
description: 'Nome do Produto',
})
@ApiBearerAuth()
@UseGuards(AuthGuard)
@ApiResponse({
status: 200,
description: 'Produtos da empresa encontrados',
type: Array<CreateProductDto>,
})
@Get('mine/:name')
async findProductByName(
@Request() req: AuthenticatedRequest,
@Param('name') name: string,
) {
return await this.productService.findByName(req.user.sub, name);
}
@ApiOperation({ summary: 'Adiciona uma produto' })
@ApiResponse({ status: 201, description: 'Produto adicionado com sucesso' })
......@@ -32,9 +71,15 @@ export class ProductsController {
@ApiBearerAuth()
@UseGuards(AuthGuard)
@Post()
async create(@Body() product: CreateProductDto) {
async create(
@Body() product: CreateProductDto,
@Request() req: AuthenticatedRequest,
) {
try {
const newProduct = await this.productService.create(product);
const newProduct = await this.productService.create(
product,
req.user.sub,
);
return {
message: 'Produto adicionado com sucesso!',
product: newProduct,
......@@ -56,9 +101,17 @@ export class ProductsController {
description: 'ID do Produto',
})
@Put(':id')
async update(@Param('id') id: number, @Body() product: CreateProductDto) {
async update(
@Param('id') id: number,
@Body() product: CreateProductDto,
@Request() req: AuthenticatedRequest,
) {
try {
const updatedProduct = await this.productService.update(+id, product);
const updatedProduct = await this.productService.update(
+id,
product,
req.user.sub,
);
return {
message: 'Produto atualizado com sucesso!',
product: updatedProduct,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment