Compare commits

..

2 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
6d24474162 Merge pull request #663 from bigcapitalhq/fix-uncategorize-bank-transaction
fix: Un-categorize bank transactions
2024-09-07 13:27:11 +02:00
Ahmed Bouhuolia
5962b990c4 fix: Uncategorize bank transactions 2024-09-07 13:26:02 +02:00
8 changed files with 24 additions and 155 deletions

View File

@@ -109,7 +109,6 @@
"rtl-detect": "^1.0.4",
"socket.io": "^4.7.4",
"source-map-loader": "^4.0.1",
"swagger-ui-express": "^5.0.1",
"tmp-promise": "^3.0.3",
"ts-transformer-keys": "^0.4.2",
"tsyringe": "^4.3.0",

View File

@@ -5,14 +5,7 @@ import { body, param } from 'express-validator';
import BaseController from '@/api/controllers/BaseController';
import { AttachmentsApplication } from '@/services/Attachments/AttachmentsApplication';
import { AttachmentUploadPipeline } from '@/services/Attachments/S3UploadPipeline';
import {
ApiOperation,
ApiResponse,
ApiTags,
Route,
} from '@/decorators/swagger-decorators';
@ApiTags('Attachments')
@Service()
export class AttachmentsController extends BaseController {
@Inject()
@@ -128,26 +121,6 @@ export class AttachmentsController extends BaseController {
* @param {NextFunction} next
* @returns {Promise<Response|void>}
*/
@ApiResponse({
status: 200,
description: 'Details of the given attachement',
schema: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
email: { type: 'string' },
},
},
},
})
@ApiOperation({
summary: 'Retrieve a specific details of attachment',
description: 'Get all registered users',
})
@Route('/attachments/:id')
private async getAttachment(
req: Request,
res: Response,

View File

@@ -8,11 +8,6 @@ import { IItemDTO, ItemAction, AbilitySubject } from '@/interfaces';
import { DATATYPES_LENGTH } from '@/data/DataTypes';
import CheckAbilities from '@/api/middleware/CheckPolicies';
import { ItemsApplication } from '@/services/Items/ItemsApplication';
import {
ApiOperation,
ApiResponse,
Route,
} from '@/decorators/swagger-decorators';
@Service()
export default class ItemsController extends BaseController {
@@ -203,22 +198,6 @@ export default class ItemsController extends BaseController {
* @param {Request} req
* @param {Response} res
*/
@ApiResponse({
status: 200,
description: 'Details of the given attachement',
schema: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
},
},
})
@ApiOperation({
summary: 'Creates a new item (inventory or service)',
description: 'Get all registered users',
})
@Route('/items')
private async newItem(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const itemDTO: IItemDTO = this.matchedBodyData(req);

View File

@@ -1,63 +0,0 @@
export const swaggerDocs = {
tags: {},
paths: {},
};
// Decorator to set a tag for a route
export function ApiTags(tag) {
return function (target) {
if (!swaggerDocs.tags[tag]) {
swaggerDocs.tags[tag] = { name: tag };
}
};
}
// Decorator to add an operation for a specific route
export function ApiOperation(options) {
return function (target, propertyKey, descriptor) {
const routePath = Reflect.getMetadata('path', target, propertyKey);
swaggerDocs.paths[routePath] = swaggerDocs.paths[routePath] || {};
swaggerDocs.paths[routePath].get = {
summary: options.summary,
description: options.description || '',
responses: options.responses || {
200: {
description: 'Successful Response',
},
},
};
};
}
// Decorator to define the route path
export function Route(path) {
return function (target, propertyKey, descriptor) {
Reflect.defineMetadata('path', path, target, propertyKey);
};
}
// Decorator to add a response schema for a specific route
export function ApiResponse(options) {
return function (target, propertyKey, descriptor) {
const routePath = Reflect.getMetadata('path', target, propertyKey);
if (!swaggerDocs.paths[routePath]) {
swaggerDocs.paths[routePath] = { get: {} };
}
swaggerDocs.paths[routePath].get.responses =
swaggerDocs.paths[routePath].get.responses || {};
swaggerDocs.paths[routePath].get.responses[options.status] = {
description: options.description || 'No description provided',
content: {
'application/json': {
schema: options.schema || {},
},
},
};
};
}

View File

@@ -146,6 +146,7 @@ export interface ICashflowTransactionUncategorizedPayload {
tenantId: number;
uncategorizedTransactionId: number;
uncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
oldMainUncategorizedTransaction: IUncategorizedCashflowTransaction;
oldUncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
trx: Knex.Transaction;
}

View File

@@ -33,22 +33,25 @@ export class UncategorizeCashflowTransaction {
): Promise<Array<number>> {
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
const oldUncategorizedTransaction =
const oldMainUncategorizedTransaction =
await UncategorizedCashflowTransaction.query()
.findById(uncategorizedTransactionId)
.throwIfNotFound();
validateTransactionShouldBeCategorized(oldUncategorizedTransaction);
validateTransactionShouldBeCategorized(oldMainUncategorizedTransaction);
const associatedUncategorizedTransactions =
await UncategorizedCashflowTransaction.query()
.where('categorizeRefId', oldUncategorizedTransaction.categorizeRefId)
.where('categorizeRefId', oldMainUncategorizedTransaction.categorizeRefId)
.where(
'categorizeRefType',
oldUncategorizedTransaction.categorizeRefType
);
oldMainUncategorizedTransaction.categorizeRefType
)
// Exclude the main transaction.
.whereNot('id', uncategorizedTransactionId);
const oldUncategorizedTransactions = [
oldUncategorizedTransaction,
oldMainUncategorizedTransaction,
...associatedUncategorizedTransactions,
];
const oldUncategoirzedTransactionsIds = oldUncategorizedTransactions.map(
@@ -85,6 +88,7 @@ export class UncategorizeCashflowTransaction {
{
tenantId,
uncategorizedTransactionId,
oldMainUncategorizedTransaction,
uncategorizedTransactions,
oldUncategorizedTransactions,
trx,

View File

@@ -22,32 +22,25 @@ export class DeleteCashflowTransactionOnUncategorize {
};
/**
* Deletes the cashflow transaction on uncategorize transaction.
* Deletes the cashflow transaction once uncategorize the bank transaction.
* @param {ICashflowTransactionUncategorizedPayload} payload
*/
public async deleteCashflowTransactionOnUncategorize({
tenantId,
oldUncategorizedTransactions,
oldMainUncategorizedTransaction,
trx,
}: ICashflowTransactionUncategorizedPayload) {
const _oldUncategorizedTransactions = oldUncategorizedTransactions.filter(
(transaction) => transaction.categorizeRefType === 'CashflowTransaction'
);
// Deletes the cashflow transaction.
if (_oldUncategorizedTransactions.length > 0) {
const result = await PromisePool.withConcurrency(1)
.for(_oldUncategorizedTransactions)
.process(async (oldUncategorizedTransaction) => {
await this.deleteCashflowTransactionService.deleteCashflowTransaction(
tenantId,
oldUncategorizedTransaction.categorizeRefId,
trx
);
});
if (result.errors.length > 0) {
throw new ServiceError('SOMETHING_WRONG');
}
// Cannot continue if the main transaction does not reference to cashflow type.
if (
oldMainUncategorizedTransaction.categorizeRefType !==
'CashflowTransaction'
) {
return;
}
await this.deleteCashflowTransactionService.deleteCashflowTransaction(
tenantId,
oldMainUncategorizedTransaction.categorizeRefId,
trx
);
}
}

17
pnpm-lock.yaml generated
View File

@@ -302,9 +302,6 @@ importers:
source-map-loader:
specifier: ^4.0.1
version: 4.0.2(webpack@5.91.0)
swagger-ui-express:
specifier: ^5.0.1
version: 5.0.1(express@4.19.2)
tmp-promise:
specifier: ^3.0.3
version: 3.0.3
@@ -24211,20 +24208,6 @@ packages:
stable: 0.1.8
dev: false
/swagger-ui-dist@5.17.14:
resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==}
dev: false
/swagger-ui-express@5.0.1(express@4.19.2):
resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==}
engines: {node: '>= v0.10.32'}
peerDependencies:
express: '>=4.0.0 || >=5.0.0-beta'
dependencies:
express: 4.19.2
swagger-ui-dist: 5.17.14
dev: false
/symbol-observable@1.2.0:
resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==}
engines: {node: '>=0.10.0'}