refactor(nestjs): wip

This commit is contained in:
Ahmed Bouhuolia
2025-05-28 21:32:48 +02:00
parent c51347d3ec
commit 66a2261e50
32 changed files with 206 additions and 70 deletions

View File

@@ -1,6 +1,6 @@
import { registerAs } from '@nestjs/config'; import { registerAs } from '@nestjs/config';
export default registerAs('bank-feed', () => ({ export default registerAs('bankfeed', () => ({
enabled: enabled:
process.env.BANK_FEED_ENABLED === 'true' || process.env.BANK_FEED_ENABLED === 'true' ||
process.env.BANK_FEED_ENABLED === 'yes', process.env.BANK_FEED_ENABLED === 'yes',

View File

@@ -13,6 +13,7 @@ import signupRestrictions from './signup-restrictions';
import jwt from './jwt'; import jwt from './jwt';
import mail from './mail'; import mail from './mail';
import loops from './loops'; import loops from './loops';
import bankfeed from './bankfeed';
export const config = [ export const config = [
systemDatabase, systemDatabase,
@@ -29,5 +30,6 @@ export const config = [
signupRestrictions, signupRestrictions,
jwt, jwt,
mail, mail,
loops loops,
bankfeed,
]; ];

View File

@@ -89,6 +89,7 @@ import { CurrenciesModule } from '../Currencies/Currencies.module';
import { MiscellaneousModule } from '../Miscellaneous/Miscellaneous.module'; import { MiscellaneousModule } from '../Miscellaneous/Miscellaneous.module';
import { UsersModule } from '../UsersModule/Users.module'; import { UsersModule } from '../UsersModule/Users.module';
import { ContactsModule } from '../Contacts/Contacts.module'; import { ContactsModule } from '../Contacts/Contacts.module';
import { BankingPlaidModule } from '../BankingPlaid/BankingPlaid.module';
@Module({ @Module({
imports: [ imports: [
@@ -186,6 +187,7 @@ import { ContactsModule } from '../Contacts/Contacts.module';
BankingTransactionsExcludeModule, BankingTransactionsExcludeModule,
BankingTransactionsRegonizeModule, BankingTransactionsRegonizeModule,
BankingMatchingModule, BankingMatchingModule,
BankingPlaidModule,
TransactionsLockingModule, TransactionsLockingModule,
SettingsModule, SettingsModule,
FeaturesModule, FeaturesModule,

View File

@@ -0,0 +1,22 @@
import { Body, Controller, Post } from '@nestjs/common';
import { PlaidApplication } from './PlaidApplication';
import { PlaidItemDto } from './dtos/PlaidItem.dto';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
@Controller('banking/plaid')
@ApiTags('banking-plaid')
export class BankingPlaidController {
constructor(private readonly plaidApplication: PlaidApplication) {}
@Post('link-token')
@ApiOperation({ summary: 'Get Plaid link token' })
getLinkToken() {
return this.plaidApplication.getLinkToken();
}
@Post('exchange-token')
@ApiOperation({ summary: 'Exchange Plaid access token' })
exchangeToken(@Body() itemDTO: PlaidItemDto) {
return this.plaidApplication.exchangeToken(itemDTO);
}
}

View File

@@ -15,6 +15,7 @@ import { PlaidItemService } from './command/PlaidItem';
import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { TenancyContext } from '../Tenancy/TenancyContext.service';
import { InjectSystemModel } from '../System/SystemModels/SystemModels.module'; import { InjectSystemModel } from '../System/SystemModels/SystemModels.module';
import { SystemPlaidItem } from './models/SystemPlaidItem'; import { SystemPlaidItem } from './models/SystemPlaidItem';
import { BankingPlaidController } from './BankingPlaid.controller';
const models = [RegisterTenancyModel(PlaidItem)]; const models = [RegisterTenancyModel(PlaidItem)];
@@ -38,5 +39,6 @@ const models = [RegisterTenancyModel(PlaidItem)];
TenancyContext, TenancyContext,
], ],
exports: [...models], exports: [...models],
controllers: [BankingPlaidController]
}) })
export class BankingPlaidModule {} export class BankingPlaidModule {}

View File

@@ -3,6 +3,7 @@ import { PlaidItemService } from './command/PlaidItem';
import { PlaidWebooks } from './command/PlaidWebhooks'; import { PlaidWebooks } from './command/PlaidWebhooks';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { PlaidItemDTO } from './types/BankingPlaid.types'; import { PlaidItemDTO } from './types/BankingPlaid.types';
import { PlaidItemDto } from './dtos/PlaidItem.dto';
@Injectable() @Injectable()
export class PlaidApplication { export class PlaidApplication {
@@ -25,7 +26,7 @@ export class PlaidApplication {
* @param {PlaidItemDTO} itemDTO * @param {PlaidItemDTO} itemDTO
* @returns * @returns
*/ */
public exchangeToken(itemDTO: PlaidItemDTO): Promise<void> { public exchangeToken(itemDTO: PlaidItemDto): Promise<void> {
return this.plaidItemService.item(itemDTO); return this.plaidItemService.item(itemDTO);
} }

View File

@@ -6,11 +6,9 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { SystemPlaidItem } from '../models/SystemPlaidItem'; import { SystemPlaidItem } from '../models/SystemPlaidItem';
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
import { import { IPlaidItemCreatedEventPayload } from '../types/BankingPlaid.types';
IPlaidItemCreatedEventPayload,
PlaidItemDTO,
} from '../types/BankingPlaid.types';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
import { PlaidItemDto } from '../dtos/PlaidItem.dto';
@Injectable() @Injectable()
export class PlaidItemService { export class PlaidItemService {
@@ -33,10 +31,10 @@ export class PlaidItemService {
/** /**
* Exchanges the public token to get access token and item id and then creates * Exchanges the public token to get access token and item id and then creates
* a new Plaid item. * a new Plaid item.
* @param {PlaidItemDTO} itemDTO - Plaid item data transfer object. * @param {PlaidItemDto} itemDTO - Plaid item data transfer object.
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
public async item(itemDTO: PlaidItemDTO): Promise<void> { public async item(itemDTO: PlaidItemDto): Promise<void> {
const { publicToken, institutionId } = itemDTO; const { publicToken, institutionId } = itemDTO;
const tenant = await this.tenancyContext.getTenant(); const tenant = await this.tenancyContext.getTenant();

View File

@@ -15,6 +15,13 @@ import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable() @Injectable()
export class PlaidUpdateTransactions { export class PlaidUpdateTransactions {
/**
* Constructor method.
* @param {PlaidSyncDb} plaidSync - Plaid sync service.
* @param {UnitOfWork} uow - Unit of work.
* @param {TenantModelProxy<typeof PlaidItem>} plaidItemModel - Plaid item model.
* @param {PlaidApi} plaidClient - Plaid client.
*/
constructor( constructor(
private readonly plaidSync: PlaidSyncDb, private readonly plaidSync: PlaidSyncDb,
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
@@ -28,8 +35,7 @@ export class PlaidUpdateTransactions {
/** /**
* Handles sync the Plaid item to Bigcaptial under UOW. * Handles sync the Plaid item to Bigcaptial under UOW.
* @param {number} tenantId - Tenant id. * @param {string} plaidItemId - Plaid item id.
* @param {number} plaidItemId - Plaid item id.
* @returns {Promise<{ addedCount: number; modifiedCount: number; removedCount: number; }>} * @returns {Promise<{ addedCount: number; modifiedCount: number; removedCount: number; }>}
*/ */
public async updateTransactions(plaidItemId: string) { public async updateTransactions(plaidItemId: string) {
@@ -44,9 +50,9 @@ export class PlaidUpdateTransactions {
* - New bank accounts. * - New bank accounts.
* - Last accounts feeds updated at. * - Last accounts feeds updated at.
* - Turn on the accounts feed flag. * - Turn on the accounts feed flag.
* @param {number} tenantId - Tenant ID.
* @param {string} plaidItemId - The Plaid ID for the item. * @param {string} plaidItemId - The Plaid ID for the item.
* @returns {Promise<{ addedCount: number; modifiedCount: number; removedCount: number; }>} * @param {Knex.Transaction} trx - Knex transaction.
* @returns {Promise<{ addedCount: number; modifiedCount: number; removedCount: number; }>}
*/ */
public async updateTransactionsWork( public async updateTransactionsWork(
plaidItemId: string, plaidItemId: string,

View File

@@ -0,0 +1,11 @@
import { IsNotEmpty, IsString } from 'class-validator';
export class PlaidItemDto {
@IsString()
@IsNotEmpty()
publicToken: string;
@IsString()
@IsNotEmpty()
institutionId: string;
}

View File

@@ -1,5 +1,5 @@
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { Body, Controller, Delete, Param, Post } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';
import { ICreditNoteRefundDTO } from '../CreditNotes/types/CreditNotes.types'; import { ICreditNoteRefundDTO } from '../CreditNotes/types/CreditNotes.types';
import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service'; import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service';
import { RefundCreditNote } from './models/RefundCreditNote'; import { RefundCreditNote } from './models/RefundCreditNote';
@@ -12,6 +12,14 @@ export class CreditNoteRefundsController {
private readonly creditNotesRefundsApplication: CreditNotesRefundsApplication, private readonly creditNotesRefundsApplication: CreditNotesRefundsApplication,
) {} ) {}
@Get(':creditNoteId/refunds')
@ApiOperation({ summary: 'Retrieve the credit note graph.' })
getCreditNoteRefunds(@Param('creditNoteId') creditNoteId: number) {
return this.creditNotesRefundsApplication.getCreditNoteRefunds(
creditNoteId,
);
}
/** /**
* Create a refund credit note. * Create a refund credit note.
* @param {number} creditNoteId - The credit note ID. * @param {number} creditNoteId - The credit note ID.

View File

@@ -6,6 +6,7 @@ import { RefundSyncCreditNoteBalanceService } from './commands/RefundSyncCreditN
import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service'; import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service';
import { CreditNoteRefundsController } from './CreditNoteRefunds.controller'; import { CreditNoteRefundsController } from './CreditNoteRefunds.controller';
import { CreditNotesModule } from '../CreditNotes/CreditNotes.module'; import { CreditNotesModule } from '../CreditNotes/CreditNotes.module';
import { GetCreditNoteRefundsService } from './queries/GetCreditNoteRefunds.service';
@Module({ @Module({
imports: [forwardRef(() => CreditNotesModule)], imports: [forwardRef(() => CreditNotesModule)],
@@ -15,10 +16,9 @@ import { CreditNotesModule } from '../CreditNotes/CreditNotes.module';
RefundCreditNoteService, RefundCreditNoteService,
RefundSyncCreditNoteBalanceService, RefundSyncCreditNoteBalanceService,
CreditNotesRefundsApplication, CreditNotesRefundsApplication,
GetCreditNoteRefundsService,
], ],
exports: [ exports: [RefundSyncCreditNoteBalanceService],
RefundSyncCreditNoteBalanceService
],
controllers: [CreditNoteRefundsController], controllers: [CreditNoteRefundsController],
}) })
export class CreditNoteRefundsModule {} export class CreditNoteRefundsModule {}

View File

@@ -5,16 +5,27 @@ import { DeleteRefundCreditNoteService } from './commands/DeleteRefundCreditNote
import { RefundCreditNoteService } from './commands/RefundCreditNote.service'; import { RefundCreditNoteService } from './commands/RefundCreditNote.service';
import { RefundSyncCreditNoteBalanceService } from './commands/RefundSyncCreditNoteBalance'; import { RefundSyncCreditNoteBalanceService } from './commands/RefundSyncCreditNoteBalance';
import { CreditNoteRefundDto } from './dto/CreditNoteRefund.dto'; import { CreditNoteRefundDto } from './dto/CreditNoteRefund.dto';
import { GetCreditNoteRefundsService } from './queries/GetCreditNoteRefunds.service';
@Injectable() @Injectable()
export class CreditNotesRefundsApplication { export class CreditNotesRefundsApplication {
constructor( constructor(
private readonly createRefundCreditNoteService: CreateRefundCreditNoteService, private readonly createRefundCreditNoteService: CreateRefundCreditNoteService,
private readonly deleteRefundCreditNoteService: DeleteRefundCreditNoteService, private readonly deleteRefundCreditNoteService: DeleteRefundCreditNoteService,
private readonly getCreditNoteRefundsService: GetCreditNoteRefundsService,
private readonly refundCreditNoteService: RefundCreditNoteService, private readonly refundCreditNoteService: RefundCreditNoteService,
private readonly refundSyncCreditNoteBalanceService: RefundSyncCreditNoteBalanceService, private readonly refundSyncCreditNoteBalanceService: RefundSyncCreditNoteBalanceService,
) {} ) {}
/**
* Retrieve the credit note graph.
* @param {number} creditNoteId - Credit note id.
* @returns {Promise<IRefundCreditNotePOJO[]>}
*/
public getCreditNoteRefunds(creditNoteId: number) {
return this.getCreditNoteRefundsService.getCreditNoteRefunds(creditNoteId);
}
/** /**
* Create a refund credit note. * Create a refund credit note.
* @param {number} creditNoteId - The credit note ID. * @param {number} creditNoteId - The credit note ID.

View File

@@ -6,7 +6,7 @@ import { IRefundCreditNotePOJO } from '../types/CreditNoteRefunds.types';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable() @Injectable()
export class ListCreditNoteRefunds { export class GetCreditNoteRefundsService {
constructor( constructor(
private readonly transformer: TransformerInjectable, private readonly transformer: TransformerInjectable,
@@ -18,7 +18,7 @@ export class ListCreditNoteRefunds {
/** /**
* Retrieve the credit note graph. * Retrieve the credit note graph.
* @param {number} creditNoteId * @param {number} creditNoteId - Credit note id.
* @returns {Promise<IRefundCreditNotePOJO[]>} * @returns {Promise<IRefundCreditNotePOJO[]>}
*/ */
public async getCreditNoteRefunds( public async getCreditNoteRefunds(

View File

@@ -0,0 +1,39 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { GetCreditNoteAssociatedAppliedInvoices } from './queries/GetCreditNoteAssociatedAppliedInvoices.service';
@Controller('credit-notes')
@ApiTags('credit-notes-apply-invoice')
export class CreditNotesApplyInvoiceController {
constructor(
private readonly getCreditNoteAssociatedAppliedInvoicesService: GetCreditNoteAssociatedAppliedInvoices,
) {}
@Get(':creditNoteId/applied-invoices')
@ApiOperation({ summary: 'Applied credit note to invoices' })
@ApiResponse({
status: 200,
description: 'Credit note successfully applied to invoices',
})
@ApiResponse({ status: 404, description: 'Credit note not found' })
@ApiResponse({ status: 400, description: 'Invalid input data' })
appliedCreditNoteToInvoices(@Param('creditNoteId') creditNoteId: number) {
return this.getCreditNoteAssociatedAppliedInvoicesService.getCreditAssociatedAppliedInvoices(
creditNoteId,
);
}
@Post(':creditNoteId/apply-invoices')
@ApiOperation({ summary: 'Apply credit note to invoices' })
@ApiResponse({
status: 200,
description: 'Credit note successfully applied to invoices',
})
@ApiResponse({ status: 404, description: 'Credit note not found' })
@ApiResponse({ status: 400, description: 'Invalid input data' })
applyCreditNoteToInvoices(@Param('creditNoteId') creditNoteId: number) {
return this.getCreditNoteAssociatedAppliedInvoicesService.getCreditAssociatedAppliedInvoices(
creditNoteId,
);
}
}

View File

@@ -8,6 +8,7 @@ import { PaymentsReceivedModule } from '../PaymentReceived/PaymentsReceived.modu
import { CreditNotesModule } from '../CreditNotes/CreditNotes.module'; import { CreditNotesModule } from '../CreditNotes/CreditNotes.module';
import { GetCreditNoteAssociatedAppliedInvoices } from './queries/GetCreditNoteAssociatedAppliedInvoices.service'; import { GetCreditNoteAssociatedAppliedInvoices } from './queries/GetCreditNoteAssociatedAppliedInvoices.service';
import { GetCreditNoteAssociatedInvoicesToApply } from './queries/GetCreditNoteAssociatedInvoicesToApply.service'; import { GetCreditNoteAssociatedInvoicesToApply } from './queries/GetCreditNoteAssociatedInvoicesToApply.service';
import { CreditNotesApplyInvoiceController } from './CreditNotesApplyInvoice.controller';
@Module({ @Module({
providers: [ providers: [
@@ -16,12 +17,11 @@ import { GetCreditNoteAssociatedInvoicesToApply } from './queries/GetCreditNoteA
CreditNoteApplyToInvoices, CreditNoteApplyToInvoices,
CreditNoteApplySyncInvoicesCreditedAmount, CreditNoteApplySyncInvoicesCreditedAmount,
CreditNoteApplySyncCredit, CreditNoteApplySyncCredit,
// GetCreditNoteAssociatedAppliedInvoices, GetCreditNoteAssociatedAppliedInvoices,
// GetCreditNoteAssociatedInvoicesToApply GetCreditNoteAssociatedInvoicesToApply,
],
exports: [
DeleteCustomerLinkedCreditNoteService,
], ],
exports: [DeleteCustomerLinkedCreditNoteService],
imports: [PaymentsReceivedModule, forwardRef(() => CreditNotesModule)], imports: [PaymentsReceivedModule, forwardRef(() => CreditNotesModule)],
controllers: [CreditNotesApplyInvoiceController],
}) })
export class CreditNotesApplyInvoiceModule {} export class CreditNotesApplyInvoiceModule {}

View File

@@ -7,9 +7,16 @@ import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable() @Injectable()
export class GetCreditNoteAssociatedAppliedInvoices { export class GetCreditNoteAssociatedAppliedInvoices {
/**
* @param {TransformerInjectable} transformer - The transformer service.
* @param {TenantModelProxy<typeof CreditNoteAppliedInvoice>} creditNoteAppliedInvoiceModel - The credit note applied invoice model.
* @param {TenantModelProxy<typeof CreditNote>} creditNoteModel - The credit note model.
*/
constructor( constructor(
private readonly transformer: TransformerInjectable, private readonly transformer: TransformerInjectable,
private readonly creditNoteAppliedInvoiceModel: typeof CreditNoteAppliedInvoice,
@Inject(CreditNoteAppliedInvoice.name)
private readonly creditNoteAppliedInvoiceModel: TenantModelProxy<typeof CreditNoteAppliedInvoice>,
@Inject(CreditNote.name) @Inject(CreditNote.name)
private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>, private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>,
@@ -29,7 +36,7 @@ export class GetCreditNoteAssociatedAppliedInvoices {
.findById(creditNoteId) .findById(creditNoteId)
.throwIfNotFound(); .throwIfNotFound();
const appliedToInvoices = await this.creditNoteAppliedInvoiceModel const appliedToInvoices = await this.creditNoteAppliedInvoiceModel()
.query() .query()
.where('credit_note_id', creditNoteId) .where('credit_note_id', creditNoteId)
.withGraphFetched('saleInvoice') .withGraphFetched('saleInvoice')

View File

@@ -10,7 +10,7 @@ export class GetCreditNoteAssociatedInvoicesToApply {
/** /**
* @param {TransformerInjectable} transformer - Transformer service. * @param {TransformerInjectable} transformer - Transformer service.
* @param {GetCreditNote} getCreditNote - Get credit note service. * @param {GetCreditNote} getCreditNote - Get credit note service.
* @param {typeof SaleInvoice} saleInvoiceModel - Sale invoice model. * @param {TenantModelProxy<typeof SaleInvoice>} saleInvoiceModel - Sale invoice model.
*/ */
constructor( constructor(
private transformer: TransformerInjectable, private transformer: TransformerInjectable,

View File

@@ -24,7 +24,7 @@ export class FeaturesConfigure {
}, },
{ {
name: Features.BankSyncing, name: Features.BankSyncing,
defaultValue: this.configService.get('bankSync.enabled') ?? false, defaultValue: this.configService.get('bankfeed.enabled') ?? false,
}, },
]; ];
} }

View File

@@ -74,11 +74,10 @@ export class EditItemCategoryService {
); );
// Creates item category under unit-of-work evnirement. // Creates item category under unit-of-work evnirement.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// const itemCategory = await this.itemCategoryModel()
const itemCategory = await ItemCategory.query().patchAndFetchById( .query(trx)
itemCategoryId, .patchAndFetchById(itemCategoryId, { ...itemCategoryObj });
{ ...itemCategoryObj },
);
// Triggers `onItemCategoryEdited` event. // Triggers `onItemCategoryEdited` event.
await this.eventEmitter.emitAsync(events.itemCategory.onEdited, { await this.eventEmitter.emitAsync(events.itemCategory.onEdited, {
oldItemCategory, oldItemCategory,

View File

@@ -1,6 +1,7 @@
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator'; import { IsNumber } from 'class-validator';
import { IsOptional, IsString } from 'class-validator'; import { IsString } from 'class-validator';
import { IsNotEmpty } from 'class-validator'; import { IsNotEmpty } from 'class-validator';
class CommandItemCategoryDto { class CommandItemCategoryDto {
@@ -17,16 +18,19 @@ class CommandItemCategoryDto {
}) })
description?: string; description?: string;
@ToNumber()
@IsNumber() @IsNumber()
@IsOptional() @IsOptional()
@ApiProperty({ example: 1, description: 'The cost account ID' }) @ApiProperty({ example: 1, description: 'The cost account ID' })
costAccountId?: number; costAccountId?: number;
@ToNumber()
@IsNumber() @IsNumber()
@IsOptional() @IsOptional()
@ApiProperty({ example: 1, description: 'The sell account ID' }) @ApiProperty({ example: 1, description: 'The sell account ID' })
sellAccountId?: number; sellAccountId?: number;
@ToNumber()
@IsNumber() @IsNumber()
@IsOptional() @IsOptional()
@ApiProperty({ example: 1, description: 'The inventory account ID' }) @ApiProperty({ example: 1, description: 'The inventory account ID' })

View File

@@ -18,6 +18,7 @@ import {
CreatePaymentReceivedDto, CreatePaymentReceivedDto,
EditPaymentReceivedDto, EditPaymentReceivedDto,
} from './dtos/PaymentReceived.dto'; } from './dtos/PaymentReceived.dto';
import { PaymentsReceivedPagesService } from './queries/PaymentsReceivedPages.service';
@Injectable() @Injectable()
export class PaymentReceivesApplication { export class PaymentReceivesApplication {
@@ -31,6 +32,7 @@ export class PaymentReceivesApplication {
private sendPaymentReceiveMailNotification: SendPaymentReceiveMailNotification, private sendPaymentReceiveMailNotification: SendPaymentReceiveMailNotification,
private getPaymentReceivePdfService: GetPaymentReceivedPdfService, private getPaymentReceivePdfService: GetPaymentReceivedPdfService,
private getPaymentReceivedStateService: GetPaymentReceivedStateService, private getPaymentReceivedStateService: GetPaymentReceivedStateService,
private paymentsReceivedPagesService: PaymentsReceivedPagesService,
) {} ) {}
/** /**
@@ -147,4 +149,14 @@ export class PaymentReceivesApplication {
public getPaymentReceivedState() { public getPaymentReceivedState() {
return this.getPaymentReceivedStateService.getPaymentReceivedState(); return this.getPaymentReceivedStateService.getPaymentReceivedState();
} }
/**
* Retrieve the payment received edit page.
* @param {number} paymentReceiveId - Payment receive id.
*/
public getPaymentReceivedEditPage(paymentReceiveId: number) {
return this.paymentsReceivedPagesService.getPaymentReceiveEditPage(
paymentReceiveId,
);
}
} }

View File

@@ -44,6 +44,20 @@ export class PaymentReceivesController {
); );
} }
@Get(':id/edit-page')
@ApiResponse({
status: 200,
description:
'The payment received edit page has been successfully retrieved.',
})
public getPaymentReceiveEditPage(
@Param('id', ParseIntPipe) paymentReceiveId: number,
) {
return this.paymentReceivesApplication.getPaymentReceivedEditPage(
paymentReceiveId,
);
}
@Get(':id/mail') @Get(':id/mail')
@ApiResponse({ @ApiResponse({
status: 200, status: 200,

View File

@@ -36,6 +36,7 @@ import { SendPaymentReceivedMailProcessor } from './processors/PaymentReceivedMa
import { SEND_PAYMENT_RECEIVED_MAIL_QUEUE } from './constants'; import { SEND_PAYMENT_RECEIVED_MAIL_QUEUE } from './constants';
import { PaymentsReceivedExportable } from './commands/PaymentsReceivedExportable'; import { PaymentsReceivedExportable } from './commands/PaymentsReceivedExportable';
import { PaymentsReceivedImportable } from './commands/PaymentsReceivedImportable'; import { PaymentsReceivedImportable } from './commands/PaymentsReceivedImportable';
import { PaymentsReceivedPagesService } from './queries/PaymentsReceivedPages.service';
@Module({ @Module({
controllers: [PaymentReceivesController], controllers: [PaymentReceivesController],
@@ -63,6 +64,7 @@ import { PaymentsReceivedImportable } from './commands/PaymentsReceivedImportabl
SendPaymentReceivedMailProcessor, SendPaymentReceivedMailProcessor,
PaymentsReceivedExportable, PaymentsReceivedExportable,
PaymentsReceivedImportable, PaymentsReceivedImportable,
PaymentsReceivedPagesService
], ],
exports: [ exports: [
PaymentReceivesApplication, PaymentReceivesApplication,

View File

@@ -41,11 +41,10 @@ export class PaymentsReceivedPagesService {
/** /**
* Retrieve payment receive new page receivable entries. * Retrieve payment receive new page receivable entries.
* @param {number} tenantId - Tenant id.
* @param {number} vendorId - Vendor id. * @param {number} vendorId - Vendor id.
* @return {IPaymentReceivePageEntry[]} * @return {IPaymentReceivePageEntry[]}
*/ */
public async getNewPageEntries(tenantId: number, customerId: number) { public async getNewPageEntries(customerId: number) {
// Retrieve due invoices. // Retrieve due invoices.
const entries = await this.saleInvoice() const entries = await this.saleInvoice()
.query() .query()
@@ -62,10 +61,7 @@ export class PaymentsReceivedPagesService {
* @param {number} tenantId - Tenant id. * @param {number} tenantId - Tenant id.
* @param {Integer} paymentReceiveId - Payment receive id. * @param {Integer} paymentReceiveId - Payment receive id.
*/ */
public async getPaymentReceiveEditPage( public async getPaymentReceiveEditPage(paymentReceiveId: number): Promise<{
tenantId: number,
paymentReceiveId: number,
): Promise<{
paymentReceive: Omit<PaymentReceived, 'entries'>; paymentReceive: Omit<PaymentReceived, 'entries'>;
entries: IPaymentReceivePageEntry[]; entries: IPaymentReceivePageEntry[];
}> { }> {

View File

@@ -232,7 +232,7 @@ export class SaleEstimatesController {
public async getSaleEstimate( public async getSaleEstimate(
@Param('id', ParseIntPipe) estimateId: number, @Param('id', ParseIntPipe) estimateId: number,
@Headers('accept') acceptHeader: string, @Headers('accept') acceptHeader: string,
@Res() res: Response, @Res({ passthrough: true }) res: Response,
) { ) {
if (acceptHeader.includes(AcceptType.ApplicationPdf)) { if (acceptHeader.includes(AcceptType.ApplicationPdf)) {
const pdfContent = const pdfContent =

View File

@@ -46,6 +46,12 @@ export class SaleReceiptsController {
return this.saleReceiptApplication.getSaleReceiptMail(id); return this.saleReceiptApplication.getSaleReceiptMail(id);
} }
@Get('state')
@ApiOperation({ summary: 'Retrieves the sale receipt state.' })
getSaleReceiptState() {
return this.saleReceiptApplication.getSaleReceiptState();
}
@Get(':id/mail') @Get(':id/mail')
@HttpCode(200) @HttpCode(200)
@ApiOperation({ summary: 'Retrieves the sale receipt mail.' }) @ApiOperation({ summary: 'Retrieves the sale receipt mail.' })
@@ -86,7 +92,7 @@ export class SaleReceiptsController {
required: true, required: true,
type: Number, type: Number,
description: 'The sale receipt id', description: 'The sale receipt id',
}) })
async getSaleReceipt( async getSaleReceipt(
@Param('id', ParseIntPipe) id: number, @Param('id', ParseIntPipe) id: number,
@Headers('accept') acceptHeader: string, @Headers('accept') acceptHeader: string,
@@ -135,10 +141,4 @@ export class SaleReceiptsController {
closeSaleReceipt(@Param('id', ParseIntPipe) id: number) { closeSaleReceipt(@Param('id', ParseIntPipe) id: number) {
return this.saleReceiptApplication.closeSaleReceipt(id); return this.saleReceiptApplication.closeSaleReceipt(id);
} }
@Get('state')
@ApiOperation({ summary: 'Retrieves the sale receipt state.' })
getSaleReceiptState() {
return this.saleReceiptApplication.getSaleReceiptState();
}
} }

View File

View File

View File

@@ -150,7 +150,7 @@ export function useCreditNote(id, props, requestProps) {
[t.CREDIT_NOTE, id], [t.CREDIT_NOTE, id],
{ method: 'get', url: `credit-notes/${id}`, ...requestProps }, { method: 'get', url: `credit-notes/${id}`, ...requestProps },
{ {
select: (res) => res.data.credit_note, select: (res) => res.data,
defaultData: {}, defaultData: {},
...props, ...props,
}, },
@@ -176,7 +176,7 @@ export function useCreateRefundCreditNote(props) {
return useMutation( return useMutation(
([id, values]) => ([id, values]) =>
apiRequest.post(`credit-notes/${id}/refund`, values), apiRequest.post(`credit-notes/${id}/refunds`, values),
{ {
onSuccess: (res, [id, values]) => { onSuccess: (res, [id, values]) => {
// Common invalidate queries. // Common invalidate queries.
@@ -220,9 +220,9 @@ export function useDeleteRefundCreditNote(props) {
export function useRefundCreditNote(id, props, requestProps) { export function useRefundCreditNote(id, props, requestProps) {
return useRequestQuery( return useRequestQuery(
[t.REFUND_CREDIT_NOTE, id], [t.REFUND_CREDIT_NOTE, id],
{ method: 'get', url: `credit-notes/${id}/refund`, ...requestProps }, { method: 'get', url: `credit-notes/${id}/refunds`, ...requestProps },
{ {
select: (res) => res.data.data, select: (res) => res.data,
defaultData: {}, defaultData: {},
...props, ...props,
}, },
@@ -258,11 +258,11 @@ export function useReconcileCreditNote(id, props, requestProps) {
[t.RECONCILE_CREDIT_NOTE, id], [t.RECONCILE_CREDIT_NOTE, id],
{ {
method: 'get', method: 'get',
url: `credit-notes/${id}/apply-to-invoices`, url: `credit-notes/${id}/applied-invoices`,
...requestProps, ...requestProps,
}, },
{ {
select: (res) => res.data.data, select: (res) => res.data,
defaultData: [], defaultData: [],
...props, ...props,
}, },
@@ -278,7 +278,7 @@ export function useCreateReconcileCreditNote(props) {
return useMutation( return useMutation(
([id, values]) => ([id, values]) =>
apiRequest.post(`credit-notes/${id}/apply-to-invoices`, values), apiRequest.post(`credit-notes/${id}/apply-invoices`, values),
{ {
onSuccess: (res, [id, values]) => { onSuccess: (res, [id, values]) => {
// Common invalidate queries. // Common invalidate queries.
@@ -304,7 +304,7 @@ export function useReconcileCreditNotes(id, props, requestProps) {
...requestProps, ...requestProps,
}, },
{ {
select: (res) => res.data.data, select: (res) => res.data,
defaultData: {}, defaultData: {},
...props, ...props,
}, },
@@ -319,7 +319,7 @@ export function useDeleteReconcileCredit(props) {
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useMutation( return useMutation(
(id) => apiRequest.delete(`credit-notes/applied-to-invoices/${id}`), (id) => apiRequest.delete(`credit-notes/applied-invoices/${id}`),
{ {
onSuccess: (res, id) => { onSuccess: (res, id) => {
// Common invalidate queries. // Common invalidate queries.
@@ -343,7 +343,7 @@ export function useRefundCreditTransaction(id, props, requestProps) {
[t.REFUND_CREDIT_NOTE_TRANSACTION, id], [t.REFUND_CREDIT_NOTE_TRANSACTION, id],
{ method: 'get', url: `credit-notes/refunds/${id}`, ...requestProps }, { method: 'get', url: `credit-notes/refunds/${id}`, ...requestProps },
{ {
select: (res) => res.data.refund_credit, select: (res) => res.data,
defaultData: {}, defaultData: {},
...props, ...props,
}, },
@@ -370,7 +370,7 @@ export function useGetCreditNoteState(
() => () =>
apiRequest apiRequest
.get('/credit-notes/state') .get('/credit-notes/state')
.then((res) => transformToCamelCase(res.data?.data)), .then((res) => transformToCamelCase(res.data)),
{ ...options }, { ...options },
); );
} }

View File

@@ -150,7 +150,7 @@ export function useApproveEstimate(props) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`sale-estimates/${id}/approve`), { return useMutation((id) => apiRequest.put(`sale-estimates/${id}/approve`), {
onSuccess: (res, id) => { onSuccess: (res, id) => {
// Common invalidate queries. // Common invalidate queries.
commonInvalidateQueries(queryClient); commonInvalidateQueries(queryClient);
@@ -169,7 +169,7 @@ export function useRejectEstimate(props) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`sale-estimates/${id}/reject`), { return useMutation((id) => apiRequest.put(`sale-estimates/${id}/reject`), {
onSuccess: (res, id) => { onSuccess: (res, id) => {
// Common invalidate queries. // Common invalidate queries.
commonInvalidateQueries(queryClient); commonInvalidateQueries(queryClient);
@@ -240,7 +240,7 @@ export function useEstimateSMSDetail(estimateId, props, requestProps) {
...requestProps, ...requestProps,
}, },
{ {
select: (res) => res.data.data, select: (res) => res.data,
defaultData: {}, defaultData: {},
...props, ...props,
}, },
@@ -321,7 +321,7 @@ export function useSaleEstimateMailState(
return useQuery([t.SALE_ESTIMATE_MAIL_OPTIONS, estimateId], () => return useQuery([t.SALE_ESTIMATE_MAIL_OPTIONS, estimateId], () =>
apiRequest apiRequest
.get(`sale-estimates/${estimateId}/mail/state`) .get(`sale-estimates/${estimateId}/mail/state`)
.then((res) => transformToCamelCase(res.data.data)), .then((res) => transformToCamelCase(res.data)),
); );
} }
@@ -339,7 +339,7 @@ export function useGetSaleEstimatesState(
() => () =>
apiRequest apiRequest
.get('/sale-estimates/state') .get('/sale-estimates/state')
.then((res) => transformToCamelCase(res.data?.data)), .then((res) => transformToCamelCase(res.data)),
{ ...options }, { ...options },
); );
} }

View File

@@ -36,7 +36,7 @@ export function useEditItemCategory(props) {
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useMutation( return useMutation(
([id, values]) => apiRequest.post(`item-categories/${id}`, values), ([id, values]) => apiRequest.put(`item-categories/${id}`, values),
{ {
onSuccess: (res, [id, values]) => { onSuccess: (res, [id, values]) => {
// Invalidate specific item category. // Invalidate specific item category.

View File

@@ -159,7 +159,7 @@ export function usePaymentReceive(id, props) {
[t.PAYMENT_RECEIVE, id], [t.PAYMENT_RECEIVE, id],
{ method: 'get', url: `payments-received/${id}` }, { method: 'get', url: `payments-received/${id}` },
{ {
select: (res) => res.data.payment_receive, select: (res) => res.data,
defaultData: {}, defaultData: {},
...props, ...props,
}, },
@@ -176,7 +176,7 @@ export function usePaymentReceiveEditPage(id, props) {
{ method: 'get', url: `payments-received/${id}/edit-page` }, { method: 'get', url: `payments-received/${id}/edit-page` },
{ {
select: (res) => ({ select: (res) => ({
paymentReceive: res.data.payment_receive, paymentReceive: res.data,
entries: res.data.entries, entries: res.data.entries,
}), }),
defaultData: { defaultData: {
@@ -231,7 +231,7 @@ export function usePaymentReceiveSMSDetail(
...requestProps, ...requestProps,
}, },
{ {
select: (res) => res.data.data, select: (res) => res.data,
defaultData: {}, defaultData: {},
...props, ...props,
}, },
@@ -336,7 +336,7 @@ export function usePaymentReceivedMailState(
() => () =>
apiRequest apiRequest
.get(`payments-received/${paymentReceiveId}/mail`) .get(`payments-received/${paymentReceiveId}/mail`)
.then((res) => transformToCamelCase(res.data?.data)), .then((res) => transformToCamelCase(res.data)),
); );
} }
@@ -360,7 +360,7 @@ export function usePaymentReceivedState(
() => () =>
apiRequest apiRequest
.get('/payments-received/state') .get('/payments-received/state')
.then((res) => transformToCamelCase(res.data?.data)), .then((res) => transformToCamelCase(res.data)),
{ {
...options, ...options,
}, },