diff --git a/packages/server-nest/package.json b/packages/server-nest/package.json index 925f30fc1..7e14561ac 100644 --- a/packages/server-nest/package.json +++ b/packages/server-nest/package.json @@ -20,14 +20,15 @@ "test:e2e": "jest --config ./test/jest-e2e.json --watchAll" }, "dependencies": { + "@aws-sdk/client-s3": "^3.576.0", + "@aws-sdk/s3-request-presigner": "^3.583.0", "@bigcapital/email-components": "*", "@bigcapital/pdf-templates": "*", "@bigcapital/server": "*", "@bigcapital/utils": "*", - "@liaoliaots/nestjs-redis": "^10.0.0", - "@aws-sdk/client-s3": "^3.576.0", - "@aws-sdk/s3-request-presigner": "^3.583.0", "@casl/ability": "^5.4.3", + "@lemonsqueezy/lemonsqueezy.js": "^2.2.0", + "@liaoliaots/nestjs-redis": "^10.0.0", "@nestjs/bull": "^10.2.1", "@nestjs/bullmq": "^10.2.2", "@nestjs/cache-manager": "^2.2.2", @@ -36,7 +37,7 @@ "@nestjs/core": "^10.0.0", "@nestjs/event-emitter": "^2.0.4", "@nestjs/jwt": "^10.2.0", - "@nestjs/passport": "^10.0.3", + "@nestjs/passport": "^11.0.5", "@nestjs/platform-express": "^10.0.0", "@nestjs/swagger": "^7.4.2", "@nestjs/throttler": "^6.2.1", @@ -44,7 +45,6 @@ "@types/nodemailer": "^6.4.17", "@types/passport-local": "^1.0.38", "@types/ramda": "^0.30.2", - "@lemonsqueezy/lemonsqueezy.js": "^2.2.0", "accounting": "^0.4.1", "async": "^3.2.0", "async-mutex": "^0.5.0", diff --git a/packages/server-nest/src/modules/PaymentServices/PaymentServices.controller.ts b/packages/server-nest/src/modules/PaymentServices/PaymentServices.controller.ts index cc1bccd91..30c7bb057 100644 --- a/packages/server-nest/src/modules/PaymentServices/PaymentServices.controller.ts +++ b/packages/server-nest/src/modules/PaymentServices/PaymentServices.controller.ts @@ -15,9 +15,12 @@ import { import { Request, Response, NextFunction } from 'express'; import { ApiTags } from '@nestjs/swagger'; import { PaymentServicesApplication } from './PaymentServicesApplication'; +import { PublicRoute } from '../Auth/Jwt.guard'; +import { EditPaymentMethodDTO } from './types'; @ApiTags('PaymentServices') @Controller('payment-services') +@PublicRoute() export class PaymentServicesController { constructor( private readonly paymentServicesApp: PaymentServicesApplication, @@ -53,13 +56,10 @@ export class PaymentServicesController { } @Post('/:paymentMethodId') - @UsePipes(new ValidationPipe({ whitelist: true })) async updatePaymentMethod( @Param('paymentMethodId') paymentMethodId: number, - @Body() updatePaymentMethodDTO: any, - @Req() req: Request, + @Body() updatePaymentMethodDTO: EditPaymentMethodDTO, @Res() res: Response, - @Next() next: NextFunction, ) { await this.paymentServicesApp.editPaymentMethod( paymentMethodId, diff --git a/packages/server-nest/src/modules/PaymentServices/PaymentServices.module.ts b/packages/server-nest/src/modules/PaymentServices/PaymentServices.module.ts index 9ed4d17bf..5d24da538 100644 --- a/packages/server-nest/src/modules/PaymentServices/PaymentServices.module.ts +++ b/packages/server-nest/src/modules/PaymentServices/PaymentServices.module.ts @@ -6,8 +6,19 @@ import { GetPaymentServicesSpecificInvoice } from './queries/GetPaymentServicesS import { GetPaymentMethodsStateService } from './queries/GetPaymentMethodsState'; import { PaymentServicesApplication } from './PaymentServicesApplication'; import { PaymentServicesController } from './PaymentServices.controller'; +import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; +import { PaymentIntegration } from './models/PaymentIntegration.model'; +import { TransactionPaymentServiceEntry } from './models/TransactionPaymentServiceEntry.model'; +import { StripePaymentModule } from '../StripePayment/StripePayment.module'; + +const models = [ + RegisterTenancyModel(PaymentIntegration), + RegisterTenancyModel(TransactionPaymentServiceEntry), +]; @Module({ + imports: [...models, StripePaymentModule], + exports: [...models], providers: [ DeletePaymentMethodService, EditPaymentMethodService, diff --git a/packages/server-nest/src/modules/PaymentServices/PaymentServicesApplication.ts b/packages/server-nest/src/modules/PaymentServices/PaymentServicesApplication.ts index 0205f7950..e1fa13c2b 100644 --- a/packages/server-nest/src/modules/PaymentServices/PaymentServicesApplication.ts +++ b/packages/server-nest/src/modules/PaymentServices/PaymentServicesApplication.ts @@ -1,12 +1,12 @@ -import { Service, Inject } from 'typedi'; import { GetPaymentServicesSpecificInvoice } from './queries/GetPaymentServicesSpecificInvoice'; import { DeletePaymentMethodService } from './commands/DeletePaymentMethodService'; import { EditPaymentMethodService } from './commands/EditPaymentMethodService'; import { EditPaymentMethodDTO, GetPaymentMethodsPOJO } from './types'; import { GetPaymentMethodsStateService } from './queries/GetPaymentMethodsState'; import { GetPaymentMethodService } from './queries/GetPaymentService'; +import { Injectable } from '@nestjs/common'; -@Service() +@Injectable() export class PaymentServicesApplication { constructor( private readonly getPaymentServicesSpecificInvoice: GetPaymentServicesSpecificInvoice, @@ -22,9 +22,7 @@ export class PaymentServicesApplication { * @returns {Promise} The payment services for the specified invoice. */ public async getPaymentServicesForInvoice(): Promise { - return this.getPaymentServicesSpecificInvoice.getPaymentServicesInvoice( - tenantId, - ); + return this.getPaymentServicesSpecificInvoice.getPaymentServicesInvoice(); } /** @@ -37,7 +35,7 @@ export class PaymentServicesApplication { /** * Deletes the given payment method. - * @param {number} paymentIntegrationId + * @param {number} paymentIntegrationId - Payment integration id. * @returns {Promise} */ public async deletePaymentMethod( @@ -50,8 +48,8 @@ export class PaymentServicesApplication { /** * Edits the given payment method. - * @param {number} paymentIntegrationId - * @param {EditPaymentMethodDTO} editPaymentMethodDTO + * @param {number} paymentIntegrationId - Payment integration id. + * @param {EditPaymentMethodDTO} editPaymentMethodDTO - Edit payment method DTO. * @returns {Promise} */ public async editPaymentMethod( diff --git a/packages/server-nest/src/modules/PaymentServices/commands/EditPaymentMethodService.ts b/packages/server-nest/src/modules/PaymentServices/commands/EditPaymentMethodService.ts index 1bc6f957a..fe98153bf 100644 --- a/packages/server-nest/src/modules/PaymentServices/commands/EditPaymentMethodService.ts +++ b/packages/server-nest/src/modules/PaymentServices/commands/EditPaymentMethodService.ts @@ -1,6 +1,5 @@ import { Knex } from 'knex'; import { EditPaymentMethodDTO } from '../types'; -import { TransactionPaymentServiceEntry } from '../models/TransactionPaymentServiceEntry.model'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { PaymentIntegration } from '../models/PaymentIntegration.model'; import { EventEmitter2 } from '@nestjs/event-emitter'; @@ -18,11 +17,6 @@ export class EditPaymentMethodService { private readonly paymentIntegrationModel: TenantModelProxy< typeof PaymentIntegration >, - - @Inject(TransactionPaymentServiceEntry.name) - private readonly transactionPaymentServiceEntryModel: TenantModelProxy< - typeof TransactionPaymentServiceEntry - >, ) {} /** diff --git a/packages/server-nest/src/modules/PaymentServices/models/PaymentIntegration.model.ts b/packages/server-nest/src/modules/PaymentServices/models/PaymentIntegration.model.ts index 0d66d9d8c..11c30d24e 100644 --- a/packages/server-nest/src/modules/PaymentServices/models/PaymentIntegration.model.ts +++ b/packages/server-nest/src/modules/PaymentServices/models/PaymentIntegration.model.ts @@ -1,10 +1,12 @@ -import { BaseModel } from "@/models/Model"; +import { BaseModel } from '@/models/Model'; export class PaymentIntegration extends BaseModel { + readonly name!: string; readonly service!: string; readonly paymentEnabled!: boolean; readonly payoutEnabled!: boolean; readonly accountId!: string; + readonly options!: Record; static get tableName() { return 'payment_integrations'; @@ -27,7 +29,7 @@ export class PaymentIntegration extends BaseModel { } /** - * + * */ static get modifiers() { return { diff --git a/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentMethodsState.ts b/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentMethodsState.ts index 70a184ebb..98200fd5c 100644 --- a/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentMethodsState.ts +++ b/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentMethodsState.ts @@ -1,7 +1,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { GetPaymentMethodsPOJO } from '../types'; -import { isStripePaymentConfigured } from '../utils'; import { GetStripeAuthorizationLinkService } from '../../StripePayment/GetStripeAuthorizationLink'; import { PaymentIntegration } from '../models/PaymentIntegration.model'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; @@ -23,8 +22,7 @@ export class GetPaymentMethodsStateService { * @param {number} tenantId * @returns {Promise} */ - public async getPaymentMethodsState( - ): Promise { + public async getPaymentMethodsState(): Promise { const stripePayment = await this.paymentIntegrationModel() .query() .orderBy('createdAt', 'ASC') @@ -43,7 +41,7 @@ export class GetPaymentMethodsStateService { ); const stripeCurrencies = ['USD', 'EUR']; const stripeRedirectUrl = 'https://your-stripe-redirect-url.com'; - const isStripeServerConfigured = isStripePaymentConfigured(); + const isStripeServerConfigured = this.isStripePaymentConfigured(); const stripeAuthLink = this.getStripeAuthorizationLinkService.getStripeAuthLink(); @@ -64,4 +62,16 @@ export class GetPaymentMethodsStateService { }; return paymentMethodPOJO; } + + /** + * Determines if Stripe payment is configured. + * @returns {boolean} + */ + private isStripePaymentConfigured() { + return ( + this.configService.get('stripePayment.secretKey') && + this.configService.get('stripePayment.publishableKey') && + this.configService.get('stripePayment.webhooksSecret') + ); + } } diff --git a/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentService.ts b/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentService.ts index 7db731add..069ef2e0c 100644 --- a/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentService.ts +++ b/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentService.ts @@ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { GetPaymentMethodsPOJO } from '../types'; import { PaymentIntegration } from '../models/PaymentIntegration.model'; +import { ModelObject } from 'objection'; @Injectable() export class GetPaymentMethodService { @@ -18,7 +19,7 @@ export class GetPaymentMethodService { */ public async getPaymentMethod( paymentServiceId: number, - ): Promise { + ): Promise> { const stripePayment = await this.paymentIntegrationModel() .query() .findById(paymentServiceId) diff --git a/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentServicesSpecificInvoice.ts b/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentServicesSpecificInvoice.ts index eaab16921..75875f065 100644 --- a/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentServicesSpecificInvoice.ts +++ b/packages/server-nest/src/modules/PaymentServices/queries/GetPaymentServicesSpecificInvoice.ts @@ -1,33 +1,34 @@ -import { Inject, Service } from 'typedi'; -import HasTenancyService from '../Tenancy/TenancyService'; -import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; +import { Inject, Injectable } from '@nestjs/common'; +import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { GetPaymentServicesSpecificInvoiceTransformer } from './GetPaymentServicesSpecificInvoiceTransformer'; +import { PaymentIntegration } from '../models/PaymentIntegration.model'; +import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; -@Service() +@Injectable() export class GetPaymentServicesSpecificInvoice { - @Inject() - private tenancy: HasTenancyService; + constructor( + private readonly transform: TransformerInjectable, - @Inject() - private transform: TransformerInjectable; + @Inject(PaymentIntegration.name) + private readonly paymentIntegrationModel: TenantModelProxy< + typeof PaymentIntegration + >, + ) {} /** * Retrieves the payment services of the given invoice. - * @param {number} tenantId * @param {number} invoiceId * @returns */ - async getPaymentServicesInvoice(tenantId: number) { - const { PaymentIntegration } = this.tenancy.models(tenantId); - - const paymentGateways = await PaymentIntegration.query() + async getPaymentServicesInvoice() { + const paymentGateways = await this.paymentIntegrationModel() + .query() .modify('fullEnabled') .orderBy('name', 'ASC'); return this.transform.transform( - tenantId, paymentGateways, - new GetPaymentServicesSpecificInvoiceTransformer() + new GetPaymentServicesSpecificInvoiceTransformer(), ); } } diff --git a/packages/server-nest/src/modules/PaymentServices/types.ts b/packages/server-nest/src/modules/PaymentServices/types.ts index f3ec7b41f..5db0deef3 100644 --- a/packages/server-nest/src/modules/PaymentServices/types.ts +++ b/packages/server-nest/src/modules/PaymentServices/types.ts @@ -1,16 +1,64 @@ -export interface EditPaymentMethodDTO { - name?: string; - options?: { - bankAccountId?: number; // bank account. - clearningAccountId?: number; // current liability. +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { + IsBoolean, + IsNumber, + IsOptional, + IsString, + ValidateNested, +} from 'class-validator'; - showVisa?: boolean; - showMasterCard?: boolean; - showDiscover?: boolean; - showAmer?: boolean; - showJcb?: boolean; - showDiners?: boolean; - }; +class EditPaymentMethodOptionsDto { + @IsOptional() + @IsNumber() + bankAccountId?: number; + + @IsOptional() + @IsNumber() + clearningAccountId?: number; + + @IsOptional() + @IsBoolean() + showVisa?: boolean; + + @IsOptional() + @IsBoolean() + showMasterCard?: boolean; + + @IsOptional() + @IsBoolean() + showDiscover?: boolean; + + @IsOptional() + @IsBoolean() + showAmer?: boolean; + + @IsOptional() + @IsBoolean() + showJcb?: boolean; + + @IsOptional() + @IsBoolean() + showDiners?: boolean; +} + +export class EditPaymentMethodDTO { + @IsOptional() + @ValidateNested() + @Type(() => EditPaymentMethodOptionsDto) + @ApiPropertyOptional({ + type: () => EditPaymentMethodOptionsDto, + description: 'Edit payment method options', + }) + options?: EditPaymentMethodOptionsDto; + + @IsOptional() + @IsString() + @ApiPropertyOptional({ + type: String, + description: 'Payment method name', + }) + name?: string; } export interface GetPaymentMethodsPOJO { @@ -22,7 +70,7 @@ export interface GetPaymentMethodsPOJO { isStripeEnabled: boolean; isStripeServerConfigured: boolean; - + stripeAccountId: string | null; stripePaymentMethodId: number | null; stripePublishableKey: string | null; diff --git a/packages/server-nest/src/modules/PaymentServices/utils.ts b/packages/server-nest/src/modules/PaymentServices/utils.ts index c8ddbc844..e69de29bb 100644 --- a/packages/server-nest/src/modules/PaymentServices/utils.ts +++ b/packages/server-nest/src/modules/PaymentServices/utils.ts @@ -1,9 +0,0 @@ -import config from '@/config'; - -export const isStripePaymentConfigured = () => { - return ( - config.stripePayment.secretKey && - config.stripePayment.publishableKey && - config.stripePayment.webhooksSecret - ); -}; diff --git a/packages/server-nest/src/modules/StripePayment/StripePayment.module.ts b/packages/server-nest/src/modules/StripePayment/StripePayment.module.ts index 748668124..bfde0398d 100644 --- a/packages/server-nest/src/modules/StripePayment/StripePayment.module.ts +++ b/packages/server-nest/src/modules/StripePayment/StripePayment.module.ts @@ -33,7 +33,7 @@ const models = [InjectSystemModel(PaymentIntegration)]; StripeWebhooksSubscriber, TenancyContext, ], - exports: [StripePaymentService], + exports: [StripePaymentService, GetStripeAuthorizationLinkService], controllers: [StripeIntegrationController], }) export class StripePaymentModule {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b12c820c..f68b9ffb9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -536,8 +536,8 @@ importers: specifier: ^10.2.0 version: 10.2.0(@nestjs/common@10.4.7) '@nestjs/passport': - specifier: ^10.0.3 - version: 10.0.3(@nestjs/common@10.4.7)(passport@0.7.0) + specifier: ^11.0.5 + version: 11.0.5(@nestjs/common@10.4.7)(passport@0.7.0) '@nestjs/platform-express': specifier: ^10.0.0 version: 10.4.7(@nestjs/common@10.4.7)(@nestjs/core@10.4.7) @@ -1534,7 +1534,7 @@ packages: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -1585,7 +1585,7 @@ packages: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.583.0(@aws-sdk/client-sts@3.583.0) - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-bucket-endpoint': 3.577.0 @@ -1649,7 +1649,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/core': 3.582.0 '@aws-sdk/credential-provider-node': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.583.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -1738,7 +1738,7 @@ packages: - aws-crt dev: false - /@aws-sdk/client-sts@3.583.0(@aws-sdk/client-sso-oidc@3.583.0): + /@aws-sdk/client-sts@3.583.0: resolution: {integrity: sha512-xDMxiemPDWr9dY2Q4AyixkRnk/hvS6fs6OWxuVCz1WO47YhaAfOsEGAgQMgDLLaOfj/oLU5D14uTNBEPGh4rBA==} engines: {node: '>=16.0.0'} dependencies: @@ -1783,7 +1783,6 @@ packages: '@smithy/util-utf8': 3.0.0 tslib: 2.8.0 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt dev: false @@ -1846,7 +1845,7 @@ packages: peerDependencies: '@aws-sdk/client-sts': ^3.583.0 dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) @@ -1917,7 +1916,7 @@ packages: peerDependencies: '@aws-sdk/client-sts': ^3.577.0 dependencies: - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -1931,7 +1930,7 @@ packages: dependencies: '@aws-sdk/client-cognito-identity': 3.583.0 '@aws-sdk/client-sso': 3.583.0 - '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) + '@aws-sdk/client-sts': 3.583.0 '@aws-sdk/credential-provider-cognito-identity': 3.583.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-http': 3.582.0 @@ -7638,11 +7637,11 @@ packages: reflect-metadata: 0.2.2 dev: false - /@nestjs/passport@10.0.3(@nestjs/common@10.4.7)(passport@0.7.0): - resolution: {integrity: sha512-znJ9Y4S8ZDVY+j4doWAJ8EuuVO7SkQN3yOBmzxbGaXbvcSwFDAdGJ+OMCg52NdzIO4tQoN4pYKx8W6M0ArfFRQ==} + /@nestjs/passport@11.0.5(@nestjs/common@10.4.7)(passport@0.7.0): + resolution: {integrity: sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==} peerDependencies: - '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 - passport: ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 + '@nestjs/common': ^10.0.0 || ^11.0.0 + passport: ^0.5.0 || ^0.6.0 || ^0.7.0 dependencies: '@nestjs/common': 10.4.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) passport: 0.7.0