diff --git a/packages/server/src/common/config/bank-feed.ts b/packages/server/src/common/config/bank-feed.ts new file mode 100644 index 000000000..8c8fca1ff --- /dev/null +++ b/packages/server/src/common/config/bank-feed.ts @@ -0,0 +1,7 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('bank-feed', () => ({ + enabled: + process.env.BANK_FEED_ENABLED === 'true' || + process.env.BANK_FEED_ENABLED === 'yes', +})); diff --git a/packages/server/src/libs/chromiumly/ConvertUtils.ts b/packages/server/src/libs/chromiumly/ConvertUtils.ts index 38d27fd99..d3b405fb0 100644 --- a/packages/server/src/libs/chromiumly/ConvertUtils.ts +++ b/packages/server/src/libs/chromiumly/ConvertUtils.ts @@ -1,4 +1,4 @@ -import FormData from 'form-data'; +import * as FormData from 'form-data'; import { GotenbergUtils } from './GotenbergUtils'; import { PageProperties } from './_types'; diff --git a/packages/server/src/libs/chromiumly/GotenbergUtils.ts b/packages/server/src/libs/chromiumly/GotenbergUtils.ts index 63a609792..9f944826d 100644 --- a/packages/server/src/libs/chromiumly/GotenbergUtils.ts +++ b/packages/server/src/libs/chromiumly/GotenbergUtils.ts @@ -1,5 +1,5 @@ -import FormData from 'form-data'; -import Axios from 'axios'; +import * as FormData from 'form-data'; +import { Axios } from 'axios'; export class GotenbergUtils { public static assert(condition: boolean, message: string): asserts condition { @@ -10,12 +10,12 @@ export class GotenbergUtils { public static async fetch(endpoint: string, data: FormData): Promise { try { - const response = await Axios.post(endpoint, data, { + const response = await new Axios({ headers: { ...data.getHeaders(), }, responseType: 'arraybuffer', // This ensures you get a Buffer bac - }); + }).post(endpoint, data); return response.data; } catch (error) { console.error(error); diff --git a/packages/server/src/libs/chromiumly/HTMLConvert.ts b/packages/server/src/libs/chromiumly/HTMLConvert.ts index 3eb109405..af34d3d43 100644 --- a/packages/server/src/libs/chromiumly/HTMLConvert.ts +++ b/packages/server/src/libs/chromiumly/HTMLConvert.ts @@ -1,5 +1,5 @@ import { constants, createReadStream, PathLike, promises } from 'fs'; -import FormData from 'form-data'; +import * as FormData from 'form-data'; import { GotenbergUtils } from './GotenbergUtils'; import { IConverter, PageProperties } from './_types'; import { PdfFormat, ChromiumRoute } from './_types'; diff --git a/packages/server/src/libs/chromiumly/UrlConvert.ts b/packages/server/src/libs/chromiumly/UrlConvert.ts index d1a462124..50c5b1c2f 100644 --- a/packages/server/src/libs/chromiumly/UrlConvert.ts +++ b/packages/server/src/libs/chromiumly/UrlConvert.ts @@ -1,4 +1,4 @@ -import FormData from 'form-data'; +import * as FormData from 'form-data'; import { IConverter, PageProperties, PdfFormat, ChromiumRoute } from './_types'; import { ConverterUtils } from './ConvertUtils'; import { Converter } from './Converter'; diff --git a/packages/server/src/modules/Attachments/Attachment.module.ts b/packages/server/src/modules/Attachments/Attachment.module.ts index dbe8c388f..638e32e01 100644 --- a/packages/server/src/modules/Attachments/Attachment.module.ts +++ b/packages/server/src/modules/Attachments/Attachment.module.ts @@ -33,6 +33,7 @@ const models = [ @Module({ imports: [S3Module, ...models], + exports: [...models], controllers: [AttachmentsController], providers: [ DeleteAttachment, diff --git a/packages/server/src/modules/Attachments/utils.ts b/packages/server/src/modules/Attachments/utils.ts index 1669d7d7b..ee5a34740 100644 --- a/packages/server/src/modules/Attachments/utils.ts +++ b/packages/server/src/modules/Attachments/utils.ts @@ -1,4 +1,4 @@ -import path from 'path'; +import * as path from 'path'; // import config from '@/config'; export const getUploadedObjectUri = (objectKey: string) => { diff --git a/packages/server/src/modules/ChromiumlyTenancy/ChromiumlyHtmlConvert.service.ts b/packages/server/src/modules/ChromiumlyTenancy/ChromiumlyHtmlConvert.service.ts index 0e25d396a..b1fe47f9e 100644 --- a/packages/server/src/modules/ChromiumlyTenancy/ChromiumlyHtmlConvert.service.ts +++ b/packages/server/src/modules/ChromiumlyTenancy/ChromiumlyHtmlConvert.service.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; -import path from 'path'; +import * as path from 'path'; import { promises as fs } from 'fs'; import { PageProperties, PdfFormat } from '@/libs/Chromiumly/_types'; import { UrlConverter } from '@/libs/Chromiumly/UrlConvert'; @@ -40,7 +40,7 @@ export class ChromiumlyHtmlConvert { const cleanup = async () => { await fs.unlink(filePath); - await Document.query().where('key', filename).delete(); + await this.documentModel().query().where('key', filename).delete(); }; return [filename, cleanup]; } diff --git a/packages/server/src/modules/ChromiumlyTenancy/utils.ts b/packages/server/src/modules/ChromiumlyTenancy/utils.ts index fd7bf7bce..5d031119f 100644 --- a/packages/server/src/modules/ChromiumlyTenancy/utils.ts +++ b/packages/server/src/modules/ChromiumlyTenancy/utils.ts @@ -1,4 +1,4 @@ -import path from 'path'; +import * as path from 'path'; export const PDF_FILE_SUB_DIR = '/pdf'; export const PDF_FILE_EXPIRE_IN = 40; // ms @@ -9,6 +9,5 @@ export const getPdfFilesStorageDir = (filename: string) => { export const getPdfFilePath = (filename: string) => { const storageDir = getPdfFilesStorageDir(filename); - - return path.join(global.__storage_dir, storageDir); + return path.join(global.__static_dirname, storageDir); }; diff --git a/packages/server/src/modules/Import/ImportFileMeta.ts b/packages/server/src/modules/Import/ImportFileMeta.ts index 2a9f10903..287fd6bda 100644 --- a/packages/server/src/modules/Import/ImportFileMeta.ts +++ b/packages/server/src/modules/Import/ImportFileMeta.ts @@ -6,23 +6,28 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service'; @Injectable() export class ImportFileMeta { + /** + * @param {TransformerInjectable} transformer - Transformer injectable service. + * @param {TenancyContext} tenancyContext - Tenancy context service. + * @param {typeof ImportModel} importModel - Import model. + */ constructor( private readonly transformer: TransformerInjectable, private readonly tenancyContext: TenancyContext, @Inject(ImportModel.name) - private readonly importModel: () => typeof ImportModel, + private readonly importModel: typeof ImportModel, ) {} /** * Retrieves the import meta of the given import model id. - * @param {number} importId + * @param {string} importId - Import id. */ async getImportMeta(importId: string) { const tenant = await this.tenancyContext.getTenant(); const tenantId = tenant.id; - const importFile = await this.importModel() + const importFile = await this.importModel .query() .where('tenantId', tenantId) .findOne('importId', importId); diff --git a/packages/server/src/modules/PaymentReceived/PaymentsReceived.controller.ts b/packages/server/src/modules/PaymentReceived/PaymentsReceived.controller.ts index 8ade4b9f3..da2a404e9 100644 --- a/packages/server/src/modules/PaymentReceived/PaymentsReceived.controller.ts +++ b/packages/server/src/modules/PaymentReceived/PaymentsReceived.controller.ts @@ -4,6 +4,7 @@ import { Controller, Delete, Get, + Headers, HttpCode, Param, ParseIntPipe, @@ -13,12 +14,14 @@ import { } from '@nestjs/common'; import { PaymentReceivesApplication } from './PaymentReceived.application'; import { - IPaymentReceivedCreateDTO, - IPaymentReceivedEditDTO, IPaymentsReceivedFilter, PaymentReceiveMailOptsDTO, } from './types/PaymentReceived.types'; -import { CreatePaymentReceivedDto, EditPaymentReceivedDto } from './dtos/PaymentReceived.dto'; +import { + CreatePaymentReceivedDto, + EditPaymentReceivedDto, +} from './dtos/PaymentReceived.dto'; +import { AcceptType } from '@/constants/accept-type'; @Controller('payments-received') @ApiTags('payments-received') @@ -89,7 +92,9 @@ export class PaymentReceivesController { @Get() @ApiOperation({ summary: 'Retrieves the payment received list.' }) - public getPaymentsReceived(@Query() filterDTO: Partial) { + public getPaymentsReceived( + @Query() filterDTO: Partial, + ) { return this.paymentReceivesApplication.getPaymentsReceived(filterDTO); } @@ -127,21 +132,16 @@ export class PaymentReceivesController { }) public getPaymentReceive( @Param('id', ParseIntPipe) paymentReceiveId: number, + @Headers('accept') acceptHeader: string, ) { - return this.paymentReceivesApplication.getPaymentReceive(paymentReceiveId); - } - - @Get(':id/pdf') - @ApiOperation({ summary: 'Retrieves the payment received pdf.' }) - @ApiResponse({ - status: 200, - description: 'The payment received pdf has been successfully retrieved.', - }) - public getPaymentReceivePdf( - @Param('id', ParseIntPipe) paymentReceivedId: number, - ) { - return this.paymentReceivesApplication.getPaymentReceivePdf( - paymentReceivedId, - ); + if (acceptHeader.includes(AcceptType.ApplicationPdf)) { + return this.paymentReceivesApplication.getPaymentReceivePdf( + paymentReceiveId, + ); + } else { + return this.paymentReceivesApplication.getPaymentReceive( + paymentReceiveId, + ); + } } } diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimates.controller.ts b/packages/server/src/modules/SaleEstimates/SaleEstimates.controller.ts index ca2ebef0a..b1330df62 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimates.controller.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimates.controller.ts @@ -4,12 +4,14 @@ import { Controller, Delete, Get, + Headers, HttpCode, Param, ParseIntPipe, Post, Put, Query, + Res, } from '@nestjs/common'; import { SaleEstimatesApplication } from './SaleEstimates.application'; import { @@ -21,6 +23,8 @@ import { CreateSaleEstimateDto, EditSaleEstimateDto, } from './dtos/SaleEstimate.dto'; +import { AcceptType } from '@/constants/accept-type'; +import { Response } from 'express'; @Controller('sale-estimates') @ApiTags('sale-estimates') @@ -184,18 +188,6 @@ export class SaleEstimatesController { ); } - @Get(':id/pdf') - @ApiOperation({ summary: 'Retrieves the sale estimate PDF.' }) - @ApiParam({ - name: 'id', - required: true, - type: Number, - description: 'The sale estimate id', - }) - public getSaleEstimatePdf(@Param('id', ParseIntPipe) saleEstimateId: number) { - return this.saleEstimatesApplication.getSaleEstimatePdf(saleEstimateId); - } - @Post(':id/mail') @HttpCode(200) @ApiOperation({ summary: 'Send the given sale estimate by mail.' }) @@ -237,7 +229,22 @@ export class SaleEstimatesController { type: Number, description: 'The sale estimate id', }) - public getSaleEstimate(@Param('id', ParseIntPipe) estimateId: number) { - return this.saleEstimatesApplication.getSaleEstimate(estimateId); + public async getSaleEstimate( + @Param('id', ParseIntPipe) estimateId: number, + @Headers('accept') acceptHeader: string, + @Res() res: Response, + ) { + if (acceptHeader.includes(AcceptType.ApplicationPdf)) { + const pdfContent = + await this.saleEstimatesApplication.getSaleEstimatePdf(estimateId); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + res.send(pdfContent); + } else { + return this.saleEstimatesApplication.getSaleEstimate(estimateId); + } } } diff --git a/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts b/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts index b0a3eb0c7..71a6cb94f 100644 --- a/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts +++ b/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts @@ -1,14 +1,17 @@ +import { Response } from 'express'; import { Body, Controller, Delete, Get, + Headers, HttpCode, Param, ParseIntPipe, Post, Put, Query, + Res, } from '@nestjs/common'; import { ISaleInvoiceWriteoffDTO, @@ -29,6 +32,7 @@ import { CreateSaleInvoiceDto, EditSaleInvoiceDto, } from './dtos/SaleInvoice.dto'; +import { AcceptType } from '@/constants/accept-type'; @Controller('sale-invoices') @ApiTags('sale-invoices') @@ -154,8 +158,22 @@ export class SaleInvoicesController { type: Number, description: 'The sale invoice id', }) - getSaleInvoice(@Param('id', ParseIntPipe) id: number) { - return this.saleInvoiceApplication.getSaleInvoice(id); + async getSaleInvoice( + @Param('id', ParseIntPipe) id: number, + @Headers('accept') acceptHeader: string, + @Res({ passthrough: true }) res: Response, + ) { + if (acceptHeader.includes(AcceptType.ApplicationPdf)) { + const pdfContent = await this.saleInvoiceApplication.saleInvoicePdf(id); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + res.send(pdfContent); + } else { + return this.saleInvoiceApplication.getSaleInvoice(id); + } } @Get() @@ -239,19 +257,6 @@ export class SaleInvoicesController { return this.saleInvoiceApplication.getInvoicePayments(id); } - @Get(':id/pdf') - @ApiOperation({ summary: 'Retrieves the sale invoice PDF.' }) - @ApiResponse({ status: 404, description: 'The sale invoice not found.' }) - @ApiParam({ - name: 'id', - required: true, - type: Number, - description: 'The sale invoice id', - }) - saleInvoicePdf(@Param('id', ParseIntPipe) id: number) { - return this.saleInvoiceApplication.saleInvoicePdf(id); - } - @Get(':id/html') @ApiOperation({ summary: 'Retrieves the sale invoice HTML.' }) @ApiResponse({ status: 404, description: 'The sale invoice not found.' }) diff --git a/packages/server/src/modules/SaleReceipts/SaleReceiptApplication.service.ts b/packages/server/src/modules/SaleReceipts/SaleReceiptApplication.service.ts index 56d198a6e..bccd27bbb 100644 --- a/packages/server/src/modules/SaleReceipts/SaleReceiptApplication.service.ts +++ b/packages/server/src/modules/SaleReceipts/SaleReceiptApplication.service.ts @@ -105,11 +105,9 @@ export class SaleReceiptApplication { /** * Retrieves the given sale receipt pdf. - * @param {number} tenantId * @param {number} saleReceiptId - * @returns */ - public getSaleReceiptPdf(tenantId: number, saleReceiptId: number) { + public getSaleReceiptPdf(saleReceiptId: number) { return this.getSaleReceiptPdfService.saleReceiptPdf(saleReceiptId); } diff --git a/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts b/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts index a7e1b9ff6..62c85882e 100644 --- a/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts +++ b/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts @@ -3,20 +3,24 @@ import { Controller, Delete, Get, + Headers, HttpCode, Param, ParseIntPipe, Post, Put, Query, + Res, } from '@nestjs/common'; import { SaleReceiptApplication } from './SaleReceiptApplication.service'; -import { ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; +import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger'; import { CreateSaleReceiptDto, EditSaleReceiptDto, } from './dtos/SaleReceipt.dto'; import { ISalesReceiptsFilter } from './types/SaleReceipts.types'; +import { AcceptType } from '@/constants/accept-type'; +import { Response } from 'express'; @Controller('sale-receipts') @ApiTags('sale-receipts') @@ -72,14 +76,34 @@ export class SaleReceiptsController { @Get(':id') @ApiOperation({ summary: 'Retrieves the sale receipt details.' }) + @ApiResponse({ + status: 200, + description: 'The sale receipt details have been successfully retrieved.', + }) + @ApiResponse({ status: 404, description: 'The sale receipt not found.' }) @ApiParam({ name: 'id', required: true, type: Number, description: 'The sale receipt id', - }) - getSaleReceipt(@Param('id', ParseIntPipe) id: number) { - return this.saleReceiptApplication.getSaleReceipt(id); +}) + async getSaleReceipt( + @Param('id', ParseIntPipe) id: number, + @Headers('accept') acceptHeader: string, + @Res({ passthrough: true }) res: Response, + ) { + if (acceptHeader.includes(AcceptType.ApplicationPdf)) { + const pdfContent = + await this.saleReceiptApplication.getSaleReceiptPdf(id); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + res.send(pdfContent); + } else { + return this.saleReceiptApplication.getSaleReceipt(id); + } } @Get() @@ -112,18 +136,6 @@ export class SaleReceiptsController { return this.saleReceiptApplication.closeSaleReceipt(id); } - @Get(':id/pdf') - @ApiOperation({ summary: 'Retrieves the sale receipt PDF.' }) - @ApiParam({ - name: 'id', - required: true, - type: Number, - description: 'The sale receipt id', - }) - getSaleReceiptPdf(@Param('id', ParseIntPipe) id: number) { - return this.saleReceiptApplication.getSaleReceiptPdf(0, id); - } - @Get('state') @ApiOperation({ summary: 'Retrieves the sale receipt state.' }) getSaleReceiptState() { diff --git a/packages/server/src/utils/template-render.ts b/packages/server/src/utils/template-render.ts index 54b25e1ee..9271c83fb 100644 --- a/packages/server/src/utils/template-render.ts +++ b/packages/server/src/utils/template-render.ts @@ -1,5 +1,5 @@ -import path from 'path'; -import pug from 'pug'; +import * as path from 'path'; +import * as pug from 'pug'; export function templateRender(filePath: string, options: Record) { const basePath = path.join(global.__resources_dir, '/views');