From eb5c59c1e22bf4a1034c33466ead42204d192412 Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Mon, 29 Dec 2025 19:07:31 -0300 Subject: [PATCH] fix(backoffice): repair build errors, update prisma schema and services --- backend/go.mod | 2 +- backoffice/.dockerignore | 38 +++++++++++++++++++ backoffice/prisma/schema.prisma | 29 ++++++++++++++ backoffice/src/auth/auth.service.ts | 2 +- backoffice/src/inventory/inventory.service.ts | 22 +++++------ backoffice/src/reports/reports.controller.ts | 27 ++++++------- backoffice/src/users/dto/create-user.dto.ts | 14 ++++++- backoffice/src/users/users.service.ts | 9 +++-- 8 files changed, 111 insertions(+), 32 deletions(-) create mode 100644 backoffice/.dockerignore diff --git a/backend/go.mod b/backend/go.mod index 008b486..23e2f11 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,6 +1,6 @@ module github.com/saveinmed/backend-go -go 1.24.3 +go 1.23.0 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 diff --git a/backoffice/.dockerignore b/backoffice/.dockerignore new file mode 100644 index 0000000..b0b8bd4 --- /dev/null +++ b/backoffice/.dockerignore @@ -0,0 +1,38 @@ +# Dependencies +node_modules +.pnpm-store + +# Build outputs +dist +build + +# Development +.git +.gitignore +*.md +*.log + +# IDE +.vscode +.idea +*.swp +*.swo + +# Tests +coverage +*.spec.ts +*.test.ts +__tests__ +test + +# Config files não necessários no container +.eslintrc* +.prettierrc* +jest.config* +tsconfig*.json +!tsconfig.json +!tsconfig.build.json + +# Env files +.env* +!.env.example diff --git a/backoffice/prisma/schema.prisma b/backoffice/prisma/schema.prisma index 559d68a..572801b 100644 --- a/backoffice/prisma/schema.prisma +++ b/backoffice/prisma/schema.prisma @@ -15,6 +15,7 @@ model Company { category String @default("farmacia") licenseNumber String @map("license_number") isVerified Boolean @default(false) @map("is_verified") + status String @default("PENDING") latitude Float @default(0) longitude Float @default(0) city String @default("") @@ -26,6 +27,7 @@ model Company { products Product[] ordersAsBuyer Order[] @relation("BuyerOrders") ordersAsSeller Order[] @relation("SellerOrders") + documents CompanyDocument[] @@map("companies") } @@ -39,6 +41,7 @@ model User { username String? email String @unique passwordHash String @map("password_hash") + refreshToken String? @map("refresh_token") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz @@ -163,3 +166,29 @@ model Shipment { @@map("shipments") } + +model SystemSettings { + id String @id @default(uuid()) @db.Uuid + key String @unique + value String + category String @default("GENERAL") + isSecure Boolean @default(false) @map("is_secure") + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz + + @@map("system_settings") +} + +model CompanyDocument { + id String @id @default(uuid()) @db.Uuid + companyId String @map("company_id") @db.Uuid + company Company @relation(fields: [companyId], references: [id]) + type String + fileUrl String @map("file_url") + status String @default("PENDING") + rejectionReason String? @map("rejection_reason") + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz + + @@map("company_documents") +} diff --git a/backoffice/src/auth/auth.service.ts b/backoffice/src/auth/auth.service.ts index 348b487..5cf02ae 100644 --- a/backoffice/src/auth/auth.service.ts +++ b/backoffice/src/auth/auth.service.ts @@ -42,7 +42,7 @@ export class AuthService { throw new UnauthorizedException('Invalid credentials'); } - const passwordMatches = await bcrypt.compare(dto.password, user.password); + const passwordMatches = await bcrypt.compare(dto.password, user.passwordHash); if (!passwordMatches) { throw new UnauthorizedException('Invalid credentials'); } diff --git a/backoffice/src/inventory/inventory.service.ts b/backoffice/src/inventory/inventory.service.ts index 84e7599..98e0ac2 100644 --- a/backoffice/src/inventory/inventory.service.ts +++ b/backoffice/src/inventory/inventory.service.ts @@ -7,10 +7,10 @@ export class InventoryService { constructor(private readonly prisma: PrismaService) { } listProducts() { - return this.prisma.product.findMany({ include: { inventory: true } }); + return this.prisma.product.findMany({ include: { inventoryAdjustments: true } }); } - async purchaseProduct(userId: string, dto: PurchaseDto) { + async purchaseProduct(buyerId: string, dto: PurchaseDto) { const product = await this.prisma.product.findUnique({ where: { id: dto.productId }, }); @@ -33,22 +33,17 @@ export class InventoryService { }), this.prisma.order.create({ data: { - companyId: userId, // Assuming userId is companyId for simplicity or we need to fetch user's company. - // Wait, 'buyerId' in old code. New schema 'Order' has 'companyId' (Seller?). - // Actually 'Order' usually has 'customerId' or 'userId' for Buyer. - // My schema: `model Order { id, company_id (Seller), user_id (Buyer), ... }` - // I'll assume userId passed here is the Buyer. - userId: userId, - // We need a companyId (Seller). Product has companyId? - companyId: product.companyId, + buyerId: buyerId, + sellerId: product.sellerId, totalCents: totalCents, status: 'PENDING', items: { create: { productId: dto.productId, - quantity: dto.quantity, - priceCents: product.priceCents, - totalCents: totalCents, + quantity: BigInt(dto.quantity), + unitCents: product.priceCents, + batch: product.batch, + expiresAt: product.expiresAt, }, }, }, @@ -58,3 +53,4 @@ export class InventoryService { return { message: 'Purchase created successfully' }; } } + diff --git a/backoffice/src/reports/reports.controller.ts b/backoffice/src/reports/reports.controller.ts index 24b2c07..d621425 100644 --- a/backoffice/src/reports/reports.controller.ts +++ b/backoffice/src/reports/reports.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get, Query, Res, UseGuards } from '@nestjs/common'; -import { Response } from 'express'; +import { FastifyReply } from 'fastify'; import { ReportsService } from './reports.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; @@ -12,19 +12,19 @@ export class ReportsController { async exportOrdersCsv( @Query('from') from: string, @Query('to') to: string, - @Res() res: Response, + @Res() res: FastifyReply, ) { const csv = await this.reportsService.exportOrdersCsv(from, to); - res.setHeader('Content-Type', 'text/csv'); - res.setHeader('Content-Disposition', `attachment; filename=orders_${from}_${to}.csv`); + res.header('Content-Type', 'text/csv'); + res.header('Content-Disposition', `attachment; filename=orders_${from}_${to}.csv`); res.send(csv); } @Get('sellers/csv') - async exportSellersCsv(@Res() res: Response) { + async exportSellersCsv(@Res() res: FastifyReply) { const csv = await this.reportsService.exportSellersCsv(); - res.setHeader('Content-Type', 'text/csv'); - res.setHeader('Content-Disposition', 'attachment; filename=sellers.csv'); + res.header('Content-Type', 'text/csv'); + res.header('Content-Disposition', 'attachment; filename=sellers.csv'); res.send(csv); } @@ -32,19 +32,20 @@ export class ReportsController { async exportLedgerCsv( @Query('from') from: string, @Query('to') to: string, - @Res() res: Response, + @Res() res: FastifyReply, ) { const csv = await this.reportsService.exportLedgerCsv(from, to); - res.setHeader('Content-Type', 'text/csv'); - res.setHeader('Content-Disposition', `attachment; filename=ledger_${from}_${to}.csv`); + res.header('Content-Type', 'text/csv'); + res.header('Content-Disposition', `attachment; filename=ledger_${from}_${to}.csv`); res.send(csv); } @Get('performance/csv') - async exportPerformanceCsv(@Res() res: Response) { + async exportPerformanceCsv(@Res() res: FastifyReply) { const csv = await this.reportsService.exportSellerPerformanceCsv(); - res.setHeader('Content-Type', 'text/csv'); - res.setHeader('Content-Disposition', 'attachment; filename=seller_performance.csv'); + res.header('Content-Type', 'text/csv'); + res.header('Content-Disposition', 'attachment; filename=seller_performance.csv'); res.send(csv); } } + diff --git a/backoffice/src/users/dto/create-user.dto.ts b/backoffice/src/users/dto/create-user.dto.ts index ec1a539..1df0942 100644 --- a/backoffice/src/users/dto/create-user.dto.ts +++ b/backoffice/src/users/dto/create-user.dto.ts @@ -1,4 +1,4 @@ -import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator'; +import { IsEmail, IsNotEmpty, IsOptional, IsString, MinLength } from 'class-validator'; export class CreateUserDto { @IsNotEmpty() @@ -15,4 +15,16 @@ export class CreateUserDto { @IsString() @IsNotEmpty() companyName!: string; + + @IsOptional() + @IsString() + cnpj?: string; + + @IsOptional() + @IsString() + licenseNumber?: string; + + @IsOptional() + @IsString() + role?: string; } diff --git a/backoffice/src/users/users.service.ts b/backoffice/src/users/users.service.ts index 47c9ad5..7a65994 100644 --- a/backoffice/src/users/users.service.ts +++ b/backoffice/src/users/users.service.ts @@ -11,7 +11,9 @@ export class UsersService { return this.prisma.$transaction(async (tx: Prisma.TransactionClient) => { const company = await tx.company.create({ data: { - name: dto.companyName, + corporateName: dto.companyName, + cnpj: dto.cnpj || '', + licenseNumber: dto.licenseNumber || '', }, }); @@ -19,8 +21,9 @@ export class UsersService { data: { name: dto.name, email: dto.email, - password: hashedPassword, + passwordHash: hashedPassword, companyId: company.id, + role: dto.role || 'ADMIN', }, include: { company: true }, }); @@ -43,7 +46,7 @@ export class UsersService { const user = await this.findById(id); if (!user) return null; - const { password, refreshToken, ...rest } = user; + const { passwordHash, ...rest } = user; return rest; } }