fix(backoffice): repair build errors, update prisma schema and services
This commit is contained in:
parent
5c59e7b5a1
commit
eb5c59c1e2
8 changed files with 111 additions and 32 deletions
|
|
@ -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
38
backoffice/.dockerignore
Normal 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
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue