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
go 1.24.3
go 1.23.0
require (
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")
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")
}

View file

@ -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');
}

View file

@ -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' };
}
}

View file

@ -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);
}
}

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 {
@IsNotEmpty()
@ -15,4 +15,16 @@ export class CreateUserDto {
@IsString()
@IsNotEmpty()
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) => {
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;
}
}