import { BadRequestException, Body, Controller, Delete, HttpCode, Param, ParseUUIDPipe, Patch, Post, UploadedFile, UseInterceptors, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { ApiBearerAuth, ApiBody, ApiConsumes, ApiCreatedResponse, ApiForbiddenResponse, ApiNoContentResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, ApiUnauthorizedResponse, } from '@nestjs/swagger'; import { CurrentUser } from '../../../common/decorators/current-user.decorator'; import { RequirePrivilege } from '../../../common/decorators/require-privilege.decorator'; import { BEARER_AUTH_NAME } from '../../../common/swagger/setup-swagger'; import { isAllowedCsvUpload } from '../shared/sales-fields'; import { SALES_INVOICE_PRIVILEGE_KEYS } from './sales-invoices-read.controller'; import { SalesInvoicesService } from './sales-invoices.service'; import { BulkIdsDto, BulkStatusDto, CreateSalesInvoiceDto, SalesInvoiceDto, UpdateSalesInvoiceDto, UpdateSalesInvoiceStatusDto, } from './dto/sales-invoice.dto'; @ApiTags('sales-invoices') @ApiBearerAuth(BEARER_AUTH_NAME) @Controller('sales-invoices') export class SalesInvoicesWriteController { constructor(private readonly salesInvoicesService: SalesInvoicesService) {} @Post('import') @RequirePrivilege(SALES_INVOICE_PRIVILEGE_KEYS, 'import') @UseInterceptors( FileInterceptor('file', { limits: { fileSize: 1_048_576 }, fileFilter: (_req, file, cb) => { if (!isAllowedCsvUpload(file)) { cb(new BadRequestException('Only CSV files are allowed'), false); return; } cb(null, true); }, }), ) @ApiConsumes('multipart/form-data') @ApiBody({ schema: { type: 'object', properties: { file: { type: 'string', format: 'binary' }, }, required: ['file'], }, }) @ApiOperation({ summary: 'Import sales invoices from CSV' }) @ApiOkResponse({ schema: { properties: { imported: { type: 'number' } } }, }) @ApiUnauthorizedResponse() @ApiForbiddenResponse() importCsv( @UploadedFile() file: { buffer?: Buffer } | undefined, @CurrentUser('id') userId: string, ): Promise<{ imported: number }> { const csv = file?.buffer?.toString('utf8') ?? ''; return this.salesInvoicesService.importCsv(csv, userId); } @Post('bulk-delete') @HttpCode(200) @RequirePrivilege(SALES_INVOICE_PRIVILEGE_KEYS, 'delete') @ApiOperation({ summary: 'Bulk delete sales invoices' }) @ApiOkResponse({ schema: { properties: { deleted: { type: 'number' } } }, }) @ApiUnauthorizedResponse() @ApiForbiddenResponse() bulkDelete(@Body() dto: BulkIdsDto): Promise<{ deleted: number }> { return this.salesInvoicesService.bulkDelete(dto.ids); } @Post('bulk-status') @HttpCode(200) @RequirePrivilege(SALES_INVOICE_PRIVILEGE_KEYS, 'update') @ApiOperation({ summary: 'Bulk update sales invoice status' }) @ApiOkResponse({ schema: { properties: { updated: { type: 'number' } } }, }) @ApiUnauthorizedResponse() @ApiForbiddenResponse() bulkStatus( @Body() dto: BulkStatusDto, @CurrentUser('id') userId: string, ): Promise<{ updated: number }> { return this.salesInvoicesService.bulkUpdateStatus( dto.ids, dto.status, userId, ); } @Post() @RequirePrivilege(SALES_INVOICE_PRIVILEGE_KEYS, 'create') @ApiOperation({ summary: 'Create sales invoice' }) @ApiCreatedResponse({ type: SalesInvoiceDto }) @ApiUnauthorizedResponse() @ApiForbiddenResponse() create( @Body() dto: CreateSalesInvoiceDto, @CurrentUser('id') userId: string, ): Promise { return this.salesInvoicesService.create({ code: dto.code, salesOrderId: dto.salesOrderId, packingSlipId: dto.packingSlipId, date: dto.date, salesPersonId: dto.salesPersonId, branchId: dto.branchId, divisionId: dto.divisionId, customerId: dto.customerId, address: dto.address, latitude: dto.latitude, longitude: dto.longitude, notes: dto.notes, products: dto.products, status: dto.status, userId, }); } @Patch(':id/status') @RequirePrivilege(SALES_INVOICE_PRIVILEGE_KEYS, 'update') @ApiOperation({ summary: 'Update sales invoice status' }) @ApiOkResponse({ type: SalesInvoiceDto }) @ApiNotFoundResponse() @ApiUnauthorizedResponse() @ApiForbiddenResponse() updateStatus( @Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateSalesInvoiceStatusDto, @CurrentUser('id') userId: string, ): Promise { return this.salesInvoicesService.updateStatus(id, dto.status, userId); } @Patch(':id') @RequirePrivilege(SALES_INVOICE_PRIVILEGE_KEYS, 'update') @ApiOperation({ summary: 'Update sales invoice (not status)' }) @ApiOkResponse({ type: SalesInvoiceDto }) @ApiNotFoundResponse() @ApiUnauthorizedResponse() @ApiForbiddenResponse() update( @Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateSalesInvoiceDto, @CurrentUser('id') userId: string, ): Promise { return this.salesInvoicesService.update(id, { code: dto.code, salesOrderId: dto.salesOrderId, packingSlipId: dto.packingSlipId, date: dto.date, salesPersonId: dto.salesPersonId, branchId: dto.branchId, divisionId: dto.divisionId, customerId: dto.customerId, address: dto.address, latitude: dto.latitude, longitude: dto.longitude, notes: dto.notes, products: dto.products, userId, }); } @Delete(':id') @HttpCode(204) @RequirePrivilege(SALES_INVOICE_PRIVILEGE_KEYS, 'delete') @ApiOperation({ summary: 'Delete sales invoice' }) @ApiNoContentResponse() @ApiNotFoundResponse() @ApiUnauthorizedResponse() @ApiForbiddenResponse() async delete(@Param('id', ParseUUIDPipe) id: string): Promise { await this.salesInvoicesService.delete(id); } }