fix(backoffice): repair build errors, update prisma schema and services

This commit is contained in:
Tiago Yamamoto 2025-12-29 19:07:31 -03:00
parent 5c59e7b5a1
commit eb5c59c1e2
8 changed files with 111 additions and 32 deletions

View file

@ -1,6 +1,6 @@
module github.com/saveinmed/backend-go module github.com/saveinmed/backend-go
go 1.24.3 go 1.23.0
require ( require (
github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/DATA-DOG/go-sqlmock v1.5.2

38
backoffice/.dockerignore Normal file
View file

@ -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

View file

@ -15,6 +15,7 @@ model Company {
category String @default("farmacia") category String @default("farmacia")
licenseNumber String @map("license_number") licenseNumber String @map("license_number")
isVerified Boolean @default(false) @map("is_verified") isVerified Boolean @default(false) @map("is_verified")
status String @default("PENDING")
latitude Float @default(0) latitude Float @default(0)
longitude Float @default(0) longitude Float @default(0)
city String @default("") city String @default("")
@ -26,6 +27,7 @@ model Company {
products Product[] products Product[]
ordersAsBuyer Order[] @relation("BuyerOrders") ordersAsBuyer Order[] @relation("BuyerOrders")
ordersAsSeller Order[] @relation("SellerOrders") ordersAsSeller Order[] @relation("SellerOrders")
documents CompanyDocument[]
@@map("companies") @@map("companies")
} }
@ -39,6 +41,7 @@ model User {
username String? username String?
email String @unique email String @unique
passwordHash String @map("password_hash") passwordHash String @map("password_hash")
refreshToken String? @map("refresh_token")
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
@ -163,3 +166,29 @@ model Shipment {
@@map("shipments") @@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")
}

View file

@ -42,7 +42,7 @@ export class AuthService {
throw new UnauthorizedException('Invalid credentials'); 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) { if (!passwordMatches) {
throw new UnauthorizedException('Invalid credentials'); throw new UnauthorizedException('Invalid credentials');
} }

View file

@ -7,10 +7,10 @@ export class InventoryService {
constructor(private readonly prisma: PrismaService) { } constructor(private readonly prisma: PrismaService) { }
listProducts() { 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({ const product = await this.prisma.product.findUnique({
where: { id: dto.productId }, where: { id: dto.productId },
}); });
@ -33,22 +33,17 @@ export class InventoryService {
}), }),
this.prisma.order.create({ this.prisma.order.create({
data: { data: {
companyId: userId, // Assuming userId is companyId for simplicity or we need to fetch user's company. buyerId: buyerId,
// Wait, 'buyerId' in old code. New schema 'Order' has 'companyId' (Seller?). sellerId: product.sellerId,
// 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,
totalCents: totalCents, totalCents: totalCents,
status: 'PENDING', status: 'PENDING',
items: { items: {
create: { create: {
productId: dto.productId, productId: dto.productId,
quantity: dto.quantity, quantity: BigInt(dto.quantity),
priceCents: product.priceCents, unitCents: product.priceCents,
totalCents: totalCents, batch: product.batch,
expiresAt: product.expiresAt,
}, },
}, },
}, },
@ -58,3 +53,4 @@ export class InventoryService {
return { message: 'Purchase created successfully' }; return { message: 'Purchase created successfully' };
} }
} }

View file

@ -1,5 +1,5 @@
import { Controller, Get, Query, Res, UseGuards } from '@nestjs/common'; import { Controller, Get, Query, Res, UseGuards } from '@nestjs/common';
import { Response } from 'express'; import { FastifyReply } from 'fastify';
import { ReportsService } from './reports.service'; import { ReportsService } from './reports.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
@ -12,19 +12,19 @@ export class ReportsController {
async exportOrdersCsv( async exportOrdersCsv(
@Query('from') from: string, @Query('from') from: string,
@Query('to') to: string, @Query('to') to: string,
@Res() res: Response, @Res() res: FastifyReply,
) { ) {
const csv = await this.reportsService.exportOrdersCsv(from, to); const csv = await this.reportsService.exportOrdersCsv(from, to);
res.setHeader('Content-Type', 'text/csv'); res.header('Content-Type', 'text/csv');
res.setHeader('Content-Disposition', `attachment; filename=orders_${from}_${to}.csv`); res.header('Content-Disposition', `attachment; filename=orders_${from}_${to}.csv`);
res.send(csv); res.send(csv);
} }
@Get('sellers/csv') @Get('sellers/csv')
async exportSellersCsv(@Res() res: Response) { async exportSellersCsv(@Res() res: FastifyReply) {
const csv = await this.reportsService.exportSellersCsv(); const csv = await this.reportsService.exportSellersCsv();
res.setHeader('Content-Type', 'text/csv'); res.header('Content-Type', 'text/csv');
res.setHeader('Content-Disposition', 'attachment; filename=sellers.csv'); res.header('Content-Disposition', 'attachment; filename=sellers.csv');
res.send(csv); res.send(csv);
} }
@ -32,19 +32,20 @@ export class ReportsController {
async exportLedgerCsv( async exportLedgerCsv(
@Query('from') from: string, @Query('from') from: string,
@Query('to') to: string, @Query('to') to: string,
@Res() res: Response, @Res() res: FastifyReply,
) { ) {
const csv = await this.reportsService.exportLedgerCsv(from, to); const csv = await this.reportsService.exportLedgerCsv(from, to);
res.setHeader('Content-Type', 'text/csv'); res.header('Content-Type', 'text/csv');
res.setHeader('Content-Disposition', `attachment; filename=ledger_${from}_${to}.csv`); res.header('Content-Disposition', `attachment; filename=ledger_${from}_${to}.csv`);
res.send(csv); res.send(csv);
} }
@Get('performance/csv') @Get('performance/csv')
async exportPerformanceCsv(@Res() res: Response) { async exportPerformanceCsv(@Res() res: FastifyReply) {
const csv = await this.reportsService.exportSellerPerformanceCsv(); const csv = await this.reportsService.exportSellerPerformanceCsv();
res.setHeader('Content-Type', 'text/csv'); res.header('Content-Type', 'text/csv');
res.setHeader('Content-Disposition', 'attachment; filename=seller_performance.csv'); res.header('Content-Disposition', 'attachment; filename=seller_performance.csv');
res.send(csv); res.send(csv);
} }
} }

View file

@ -1,4 +1,4 @@
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator'; import { IsEmail, IsNotEmpty, IsOptional, IsString, MinLength } from 'class-validator';
export class CreateUserDto { export class CreateUserDto {
@IsNotEmpty() @IsNotEmpty()
@ -15,4 +15,16 @@ export class CreateUserDto {
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
companyName!: string; companyName!: string;
@IsOptional()
@IsString()
cnpj?: string;
@IsOptional()
@IsString()
licenseNumber?: string;
@IsOptional()
@IsString()
role?: string;
} }

View file

@ -11,7 +11,9 @@ export class UsersService {
return this.prisma.$transaction(async (tx: Prisma.TransactionClient) => { return this.prisma.$transaction(async (tx: Prisma.TransactionClient) => {
const company = await tx.company.create({ const company = await tx.company.create({
data: { data: {
name: dto.companyName, corporateName: dto.companyName,
cnpj: dto.cnpj || '',
licenseNumber: dto.licenseNumber || '',
}, },
}); });
@ -19,8 +21,9 @@ export class UsersService {
data: { data: {
name: dto.name, name: dto.name,
email: dto.email, email: dto.email,
password: hashedPassword, passwordHash: hashedPassword,
companyId: company.id, companyId: company.id,
role: dto.role || 'ADMIN',
}, },
include: { company: true }, include: { company: true },
}); });
@ -43,7 +46,7 @@ export class UsersService {
const user = await this.findById(id); const user = await this.findById(id);
if (!user) return null; if (!user) return null;
const { password, refreshToken, ...rest } = user; const { passwordHash, ...rest } = user;
return rest; return rest;
} }
} }