feat: StorageService S3/MinIO, POST /users, invoice upload, portal dashboard §08 statuses + notifications
This commit is contained in:
@@ -15,6 +15,10 @@ export class CreatePreAlertDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
vendorTracking?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
estimatedArrival?: string;
|
||||
}
|
||||
|
||||
export class UpdatePreAlertStatusDto {
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { Controller, Get, Post, Patch, Delete, Body, Param, UseGuards } from "@nestjs/common";
|
||||
import {
|
||||
Controller, Get, Post, Patch, Delete, Body, Param, UseGuards,
|
||||
UseInterceptors, UploadedFile,
|
||||
} from "@nestjs/common";
|
||||
import { FileInterceptor } from "@nestjs/platform-express";
|
||||
import { memoryStorage } from "multer";
|
||||
import { PreAlertsService } from "./pre-alerts.service";
|
||||
import { CreatePreAlertDto, UpdatePreAlertStatusDto } from "./dto/pre-alert.dto";
|
||||
import { JwtAuthGuard, RolesGuard, Roles } from "../auth/guards/auth.guard";
|
||||
import { CurrentUser } from "../auth/decorators/current-user.decorator";
|
||||
import { StorageService } from "../storage/storage.service";
|
||||
|
||||
@Controller("pre-alerts")
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
export class PreAlertsController {
|
||||
constructor(private svc: PreAlertsService) {}
|
||||
constructor(
|
||||
private svc: PreAlertsService,
|
||||
private storage: StorageService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
findAll(@CurrentUser() user: any) {
|
||||
@@ -20,6 +29,34 @@ export class PreAlertsController {
|
||||
return this.svc.create(dto, user);
|
||||
}
|
||||
|
||||
/** Upload invoice PDF/image for a pre-alert (doc §07 / §09) */
|
||||
@Post(":id/invoice")
|
||||
@Roles("CLIENTE")
|
||||
@UseInterceptors(
|
||||
FileInterceptor("invoice", {
|
||||
storage: memoryStorage(),
|
||||
fileFilter: (_req, file, cb) => {
|
||||
const allowed = /pdf|jpg|jpeg|png|webp/;
|
||||
const ext = file.originalname.split(".").pop()?.toLowerCase() ?? "";
|
||||
cb(null, allowed.test(ext));
|
||||
},
|
||||
limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB
|
||||
}),
|
||||
)
|
||||
async uploadInvoice(
|
||||
@Param("id") id: string,
|
||||
@UploadedFile() file: Express.Multer.File,
|
||||
@CurrentUser() user: any,
|
||||
): Promise<any> {
|
||||
const url = await this.storage.saveFile(
|
||||
"invoices",
|
||||
file.originalname,
|
||||
file.buffer,
|
||||
file.mimetype,
|
||||
);
|
||||
return this.svc.attachInvoice(id, url, user);
|
||||
}
|
||||
|
||||
@Patch(":id/status")
|
||||
@Roles("OPERADOR_BODEGA", "ADMIN_EMPRESA", "SUPER_ADMIN")
|
||||
updateStatus(@Param("id") id: string, @Body() dto: UpdatePreAlertStatusDto): Promise<any> {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { PreAlertsController } from "./pre-alerts.controller";
|
||||
import { PreAlertsService } from "./pre-alerts.service";
|
||||
import { StorageModule } from "../storage/storage.module";
|
||||
import { PrismaModule } from "../prisma/prisma.module";
|
||||
|
||||
@Module({ controllers: [PreAlertsController], providers: [PreAlertsService] })
|
||||
@Module({
|
||||
imports: [PrismaModule, StorageModule],
|
||||
controllers: [PreAlertsController],
|
||||
providers: [PreAlertsService],
|
||||
})
|
||||
export class PreAlertsModule {}
|
||||
|
||||
@@ -19,17 +19,29 @@ export class PreAlertsService {
|
||||
async create(dto: CreatePreAlertDto, user: any): Promise<any> {
|
||||
return this.prisma.client.preAlert.create({
|
||||
data: {
|
||||
tenantId: user.tenantId,
|
||||
userId: user.id,
|
||||
store: dto.store,
|
||||
description: dto.description,
|
||||
declaredValue: dto.declaredValue ?? 0,
|
||||
vendorTracking: dto.vendorTracking,
|
||||
status: "PENDIENTE",
|
||||
tenantId: user.tenantId,
|
||||
userId: user.id,
|
||||
store: dto.store,
|
||||
description: dto.description,
|
||||
declaredValue: dto.declaredValue ?? 0,
|
||||
vendorTracking: dto.vendorTracking,
|
||||
estimatedArrival: dto.estimatedArrival ? new Date(dto.estimatedArrival) : undefined,
|
||||
status: "PENDIENTE",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** Attach invoice URL to a pre-alert (doc §07/§09) */
|
||||
async attachInvoice(id: string, invoiceKey: string, user: any): Promise<any> {
|
||||
const alert = await this.prisma.client.preAlert.findUnique({ where: { id } });
|
||||
if (!alert) throw new NotFoundException("Pre-alerta no encontrada.");
|
||||
if (user.role === "CLIENTE" && alert.userId !== user.id) throw new ForbiddenException();
|
||||
return this.prisma.client.preAlert.update({
|
||||
where: { id },
|
||||
data: { invoiceKey },
|
||||
});
|
||||
}
|
||||
|
||||
async updateStatus(id: string, dto: UpdatePreAlertStatusDto): Promise<any> {
|
||||
const alert = await this.prisma.client.preAlert.findUnique({ where: { id } });
|
||||
if (!alert) throw new NotFoundException("Pre-alerta no encontrada.");
|
||||
|
||||
Reference in New Issue
Block a user