mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 21:00:31 +00:00
wip
This commit is contained in:
@@ -11,7 +11,7 @@ import { ThrottlerStorageRedisService } from '@nest-lab/throttler-storage-redis'
|
||||
useFactory: (configService: ConfigService) => {
|
||||
// Use in-memory storage with very high limits for test environment
|
||||
const isTest = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined;
|
||||
|
||||
|
||||
if (isTest) {
|
||||
return {
|
||||
throttlers: [
|
||||
@@ -35,10 +35,11 @@ import { ThrottlerStorageRedisService } from '@nest-lab/throttler-storage-redis'
|
||||
const password = configService.get<string>('redis.password');
|
||||
const db = configService.get<number>('redis.db');
|
||||
|
||||
const globalTtl = configService.get<number>('throttle.global.ttl');
|
||||
const globalLimit = configService.get<number>('throttle.global.limit');
|
||||
const authTtl = configService.get<number>('throttle.auth.ttl');
|
||||
const authLimit = configService.get<number>('throttle.auth.limit');
|
||||
// Ensure we always have valid numbers with fallback defaults
|
||||
const globalTtl = configService.get<number>('throttle.global.ttl') ?? 60000;
|
||||
const globalLimit = configService.get<number>('throttle.global.limit') ?? 100;
|
||||
const authTtl = configService.get<number>('throttle.auth.ttl') ?? 60000;
|
||||
const authLimit = configService.get<number>('throttle.auth.limit') ?? 10;
|
||||
|
||||
return {
|
||||
throttlers: [
|
||||
|
||||
@@ -4,8 +4,11 @@ import { TransactionsByReferenceRepository } from './TransactionsByReferenceRepo
|
||||
import { TransactionsByReferenceService } from './TransactionsByReference.service';
|
||||
import { TransactionsByReferenceController } from './TransactionsByReference.controller';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { FinancialSheetCommonModule } from '../../common/FinancialSheetCommon.module';
|
||||
import { AccountsModule } from '@/modules/Accounts/Accounts.module';
|
||||
|
||||
@Module({
|
||||
imports: [FinancialSheetCommonModule, AccountsModule],
|
||||
providers: [
|
||||
TransactionsByReferenceRepository,
|
||||
TransactionsByReferenceApplication,
|
||||
@@ -14,4 +17,4 @@ import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
],
|
||||
controllers: [TransactionsByReferenceController],
|
||||
})
|
||||
export class TransactionsByReferenceModule {}
|
||||
export class TransactionsByReferenceModule { }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Controller, Get, Query } from '@nestjs/common';
|
||||
import { TransactionsByReferenceApplication } from './TransactionsByReferenceApplication';
|
||||
import { ITransactionsByReferenceQuery } from './TransactionsByReference.types';
|
||||
import { TransactionsByReferenceQueryDto } from './TransactionsByReferenceQuery.dto';
|
||||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
@Controller('reports/transactions-by-reference')
|
||||
@@ -8,13 +8,13 @@ import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
export class TransactionsByReferenceController {
|
||||
constructor(
|
||||
private readonly transactionsByReferenceApp: TransactionsByReferenceApplication,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
@Get()
|
||||
@ApiResponse({ status: 200, description: 'Transactions by reference' })
|
||||
@ApiOperation({ summary: 'Get transactions by reference' })
|
||||
async getTransactionsByReference(
|
||||
@Query() query: ITransactionsByReferenceQuery,
|
||||
@Query() query: TransactionsByReferenceQueryDto,
|
||||
) {
|
||||
const data = await this.transactionsByReferenceApp.getTransactions(query);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
ITransactionsByReferencePojo,
|
||||
ITransactionsByReferenceQuery,
|
||||
@@ -13,7 +13,7 @@ export class TransactionsByReferenceService {
|
||||
constructor(
|
||||
private readonly repository: TransactionsByReferenceRepository,
|
||||
private readonly tenancyContext: TenancyContext
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Retrieve accounts transactions by given reference id and type.
|
||||
@@ -23,6 +23,12 @@ export class TransactionsByReferenceService {
|
||||
public async getTransactionsByReference(
|
||||
query: ITransactionsByReferenceQuery
|
||||
): Promise<ITransactionsByReferencePojo> {
|
||||
// Validate referenceId is a valid positive number
|
||||
const referenceId = Number(query.referenceId);
|
||||
if (isNaN(referenceId) || referenceId <= 0) {
|
||||
throw new BadRequestException('referenceId must be a valid positive number');
|
||||
}
|
||||
|
||||
const filter = {
|
||||
...getTransactionsByReferenceQuery(),
|
||||
...query,
|
||||
@@ -31,7 +37,7 @@ export class TransactionsByReferenceService {
|
||||
|
||||
// Retrieve the accounts transactions of the given reference.
|
||||
const transactions = await this.repository.getTransactions(
|
||||
Number(filter.referenceId),
|
||||
referenceId,
|
||||
filter.referenceType
|
||||
);
|
||||
// Transactions by reference report.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TransactionsByReferenceQueryDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({
|
||||
description: 'The type of the reference (e.g., SaleInvoice, Bill, etc.)',
|
||||
example: 'SaleInvoice',
|
||||
required: true,
|
||||
})
|
||||
referenceType: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({
|
||||
description: 'The ID of the reference',
|
||||
example: '1',
|
||||
required: true,
|
||||
})
|
||||
referenceId: string;
|
||||
}
|
||||
@@ -47,18 +47,18 @@ export class TransactionsByReference extends FinancialSheet {
|
||||
debit: this.getAmountMeta(transaction.debit, { money: false }),
|
||||
|
||||
// @ts-ignore
|
||||
// referenceTypeFormatted: transaction.referenceTypeFormatted,
|
||||
referenceTypeFormatted: '',
|
||||
// formattedReferenceType: transaction.referenceTypeFormatted,
|
||||
formattedReferenceType: '',
|
||||
|
||||
referenceType: transaction.referenceType,
|
||||
referenceId: transaction.referenceId,
|
||||
|
||||
contactId: transaction.contactId,
|
||||
contactType: transaction.contactType,
|
||||
contactTypeFormatted: transaction.contactType,
|
||||
formattedContactType: transaction.contactType || '',
|
||||
|
||||
accountName: transaction.account.name,
|
||||
accountCode: transaction.account.code,
|
||||
accountName: transaction.account?.name || '',
|
||||
accountCode: transaction.account?.code || '',
|
||||
accountId: transaction.accountId,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ export class PaymentReceivedValidators {
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Validates the payment existance.
|
||||
@@ -79,11 +79,11 @@ export class PaymentReceivedValidators {
|
||||
const invoicesIds = paymentReceiveEntries
|
||||
.map((e: { invoiceId: number }) => e.invoiceId)
|
||||
.filter((id): id is number => id !== undefined && id !== null);
|
||||
|
||||
|
||||
if (invoicesIds.length === 0) {
|
||||
throw new ServiceError(ERRORS.INVOICES_IDS_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
const storedInvoices = await this.saleInvoiceModel()
|
||||
.query()
|
||||
.whereIn('id', invoicesIds)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Put,
|
||||
Get,
|
||||
Delete,
|
||||
Param,
|
||||
@@ -45,7 +46,7 @@ export class RolesController {
|
||||
};
|
||||
}
|
||||
|
||||
@Post(':id')
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: 'Edit an existing role' })
|
||||
@ApiParam({ name: 'id', description: 'Role ID' })
|
||||
@ApiBody({ type: EditRoleDto })
|
||||
|
||||
@@ -17,7 +17,7 @@ export class EditRoleService {
|
||||
|
||||
@Inject(Role.name)
|
||||
private readonly roleModel: TenantModelProxy<typeof Role>,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Edits details of the given role on the storage.
|
||||
@@ -30,7 +30,13 @@ export class EditRoleService {
|
||||
|
||||
// Retrieve the given role or throw not found serice error.
|
||||
const oldRole = await this.roleModel().query().findById(roleId);
|
||||
const permissions = editRoleDTO.permissions;
|
||||
// Transform permissions: map permissionId to id for Objection.js upsertGraph
|
||||
const permissions = editRoleDTO.permissions.map((perm) => ({
|
||||
id: perm.permissionId,
|
||||
subject: perm.subject,
|
||||
ability: perm.ability,
|
||||
value: perm.value,
|
||||
}));
|
||||
|
||||
// Updates the role on the storage.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
|
||||
@@ -38,7 +38,7 @@ export class CommandRolePermissionDto {
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
export class CreateRolePermissionDto extends CommandRolePermissionDto {}
|
||||
export class CreateRolePermissionDto extends CommandRolePermissionDto { }
|
||||
export class EditRolePermissionDto extends CommandRolePermissionDto {
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
@@ -83,9 +83,9 @@ export class EditRoleDto extends CommandRoleDto {
|
||||
@IsArray()
|
||||
@ArrayMinSize(1)
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CommandRolePermissionDto)
|
||||
@Type(() => EditRolePermissionDto)
|
||||
@ApiProperty({
|
||||
type: [CommandRolePermissionDto],
|
||||
type: [EditRolePermissionDto],
|
||||
description: 'The permissions of the role',
|
||||
})
|
||||
permissions: Array<EditRolePermissionDto>;
|
||||
|
||||
@@ -168,7 +168,7 @@ export class SaleReceiptsController {
|
||||
@Headers('accept') acceptHeader: string,
|
||||
@Res({ passthrough: true }) res: Response,
|
||||
) {
|
||||
if (acceptHeader.includes(AcceptType.ApplicationPdf)) {
|
||||
if (acceptHeader?.includes(AcceptType.ApplicationPdf)) {
|
||||
const [pdfContent] =
|
||||
await this.saleReceiptApplication.getSaleReceiptPdf(id);
|
||||
|
||||
@@ -177,7 +177,7 @@ export class SaleReceiptsController {
|
||||
'Content-Length': pdfContent.length,
|
||||
});
|
||||
res.send(pdfContent);
|
||||
} else if (acceptHeader.includes(AcceptType.ApplicationTextHtml)) {
|
||||
} else if (acceptHeader?.includes(AcceptType.ApplicationTextHtml)) {
|
||||
const htmlContent =
|
||||
await this.saleReceiptApplication.getSaleReceiptHtml(id);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ export class CreateSaleReceipt {
|
||||
|
||||
@Inject(Customer.name)
|
||||
private readonly customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Creates a new sale receipt with associated entries.
|
||||
@@ -89,7 +89,7 @@ export class CreateSaleReceipt {
|
||||
|
||||
// Inserts the sale receipt graph to the storage.
|
||||
const saleReceipt = await this.saleReceiptModel()
|
||||
.query()
|
||||
.query(trx)
|
||||
.upsertGraph({
|
||||
...saleReceiptObj,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user