feat(server): move all cashflow under application service

This commit is contained in:
Ahmed Bouhuolia
2024-03-07 14:19:11 +02:00
parent d87d674aba
commit 62d3e386dd
8 changed files with 138 additions and 49 deletions

View File

@@ -3,14 +3,15 @@ import { Router, Request, Response, NextFunction } from 'express';
import { param } from 'express-validator'; import { param } from 'express-validator';
import BaseController from '../BaseController'; import BaseController from '../BaseController';
import { ServiceError } from '@/exceptions'; import { ServiceError } from '@/exceptions';
import { DeleteCashflowTransaction } from '../../../services/Cashflow/DeleteCashflowTransactionService';
import CheckPolicies from '@/api/middleware/CheckPolicies'; import CheckPolicies from '@/api/middleware/CheckPolicies';
import { AbilitySubject, CashflowAction } from '@/interfaces'; import { AbilitySubject, CashflowAction } from '@/interfaces';
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
@Service() @Service()
export default class DeleteCashflowTransactionController extends BaseController { export default class DeleteCashflowTransactionController extends BaseController {
@Inject() @Inject()
private deleteCashflowService: DeleteCashflowTransaction; private cashflowApplication: CashflowApplication;
/** /**
* Controller router. * Controller router.
@@ -44,7 +45,7 @@ export default class DeleteCashflowTransactionController extends BaseController
try { try {
const { oldCashflowTransaction } = const { oldCashflowTransaction } =
await this.deleteCashflowService.deleteCashflowTransaction( await this.cashflowApplication.deleteTransaction(
tenantId, tenantId,
transactionId transactionId
); );

View File

@@ -7,14 +7,12 @@ import GetCashflowTransactionsService from '@/services/Cashflow/GetCashflowTrans
import { ServiceError } from '@/exceptions'; import { ServiceError } from '@/exceptions';
import CheckPolicies from '@/api/middleware/CheckPolicies'; import CheckPolicies from '@/api/middleware/CheckPolicies';
import { AbilitySubject, CashflowAction } from '@/interfaces'; import { AbilitySubject, CashflowAction } from '@/interfaces';
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
@Service() @Service()
export default class GetCashflowAccounts extends BaseController { export default class GetCashflowAccounts extends BaseController {
@Inject() @Inject()
private getCashflowAccountsService: GetCashflowAccountsService; private cashflowApplication: CashflowApplication;
@Inject()
private getCashflowTransactionsService: GetCashflowTransactionsService;
/** /**
* Controller router. * Controller router.
@@ -62,10 +60,7 @@ export default class GetCashflowAccounts extends BaseController {
try { try {
const cashflowAccounts = const cashflowAccounts =
await this.getCashflowAccountsService.getCashflowAccounts( await this.cashflowApplication.getCashflowAccounts(tenantId, filter);
tenantId,
filter
);
return res.status(200).send({ return res.status(200).send({
cashflow_accounts: this.transfromToResponse(cashflowAccounts), cashflow_accounts: this.transfromToResponse(cashflowAccounts),

View File

@@ -6,11 +6,12 @@ import GetCashflowTransactionsService from '@/services/Cashflow/GetCashflowTrans
import { ServiceError } from '@/exceptions'; import { ServiceError } from '@/exceptions';
import CheckPolicies from '@/api/middleware/CheckPolicies'; import CheckPolicies from '@/api/middleware/CheckPolicies';
import { AbilitySubject, CashflowAction } from '@/interfaces'; import { AbilitySubject, CashflowAction } from '@/interfaces';
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
@Service() @Service()
export default class GetCashflowAccounts extends BaseController { export default class GetCashflowAccounts extends BaseController {
@Inject() @Inject()
private getCashflowTransactionsService: GetCashflowTransactionsService; private cashflowApplication: CashflowApplication;
/** /**
* Controller router. * Controller router.
@@ -43,11 +44,11 @@ export default class GetCashflowAccounts extends BaseController {
const { transactionId } = req.params; const { transactionId } = req.params;
try { try {
const cashflowTransaction = const cashflowTransaction = await this.cashflowApplication.getTransaction(
await this.getCashflowTransactionsService.getCashflowTransaction( tenantId,
tenantId, transactionId
transactionId
); );
return res.status(200).send({ return res.status(200).send({
cashflow_transaction: this.transfromToResponse(cashflowTransaction), cashflow_transaction: this.transfromToResponse(cashflowTransaction),

View File

@@ -1,18 +1,14 @@
import { Service, Inject } from 'typedi'; import { Service, Inject } from 'typedi';
import { check, oneOf } from 'express-validator'; import { ValidationChain, check, param, query } from 'express-validator';
import { Router, Request, Response, NextFunction } from 'express'; import { Router, Request, Response, NextFunction } from 'express';
import BaseController from '../BaseController'; import BaseController from '../BaseController';
import { ServiceError } from '@/exceptions'; import { ServiceError } from '@/exceptions';
import NewCashflowTransactionService from '@/services/Cashflow/NewCashflowTransactionService';
import CheckPolicies from '@/api/middleware/CheckPolicies'; import CheckPolicies from '@/api/middleware/CheckPolicies';
import { AbilitySubject, CashflowAction } from '@/interfaces'; import { AbilitySubject, CashflowAction } from '@/interfaces';
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication'; import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
@Service() @Service()
export default class NewCashflowTransactionController extends BaseController { export default class NewCashflowTransactionController extends BaseController {
@Inject()
private newCashflowTranscationService: NewCashflowTransactionService;
@Inject() @Inject()
private cashflowApplication: CashflowApplication; private cashflowApplication: CashflowApplication;
@@ -29,6 +25,8 @@ export default class NewCashflowTransactionController extends BaseController {
); );
router.get( router.get(
'/transactions/:id/uncategorized', '/transactions/:id/uncategorized',
this.getUncategorizedTransactionsValidationSchema,
this.validationResult,
this.asyncMiddleware(this.getUncategorizedCashflowTransactions), this.asyncMiddleware(this.getUncategorizedCashflowTransactions),
this.catchServiceErrors this.catchServiceErrors
); );
@@ -62,6 +60,18 @@ export default class NewCashflowTransactionController extends BaseController {
return router; return router;
} }
/**
* Getting uncategorized transactions validation schema.
* @returns {ValidationChain}
*/
public get getUncategorizedTransactionsValidationSchema() {
return [
param('id').exists().isNumeric().toInt(),
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
];
}
/** /**
* Categorize as expense validation schema. * Categorize as expense validation schema.
*/ */
@@ -112,7 +122,7 @@ export default class NewCashflowTransactionController extends BaseController {
check('branch_id').optional({ nullable: true }).isNumeric().toInt(), check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
check('publish').default(false).isBoolean().toBoolean(), check('publish').default(false).isBoolean().toBoolean(),
]; ];
} }
/** /**
* Creates a new cashflow transaction. * Creates a new cashflow transaction.
@@ -130,7 +140,7 @@ export default class NewCashflowTransactionController extends BaseController {
try { try {
const cashflowTransaction = const cashflowTransaction =
await this.newCashflowTranscationService.newCashflowTransaction( await this.cashflowApplication.createTransaction(
tenantId, tenantId,
ownerContributionDTO, ownerContributionDTO,
userId userId
@@ -159,7 +169,7 @@ export default class NewCashflowTransactionController extends BaseController {
const { id: cashflowTransactionId } = req.params; const { id: cashflowTransactionId } = req.params;
try { try {
const data= await this.cashflowApplication.uncategorizeTransaction( const data = await this.cashflowApplication.uncategorizeTransaction(
tenantId, tenantId,
cashflowTransactionId cashflowTransactionId
); );
@@ -265,11 +275,13 @@ export default class NewCashflowTransactionController extends BaseController {
) => { ) => {
const { tenantId } = req; const { tenantId } = req;
const { id: accountId } = req.params; const { id: accountId } = req.params;
const query = this.matchedQueryData(req);
try { try {
const data = await this.cashflowApplication.getUncategorizedTransactions( const data = await this.cashflowApplication.getUncategorizedTransactions(
tenantId, tenantId,
accountId accountId,
query
); );
return res.status(200).send(data); return res.status(200).send(data);
@@ -338,8 +350,8 @@ export default class NewCashflowTransactionController extends BaseController {
{ {
type: 'UNCATEGORIZED_TRANSACTION_TYPE_INVALID', type: 'UNCATEGORIZED_TRANSACTION_TYPE_INVALID',
code: 4100, code: 4100,
} },
] ],
}); });
} }
} }

View File

@@ -156,3 +156,8 @@ export interface CategorizeTransactionAsExpenseDTO {
description: string; description: string;
branchId?: number; branchId?: number;
} }
export interface IGetUncategorizedTransactionsQuery {
page?: number;
pageSize?: number;
}

View File

@@ -5,19 +5,33 @@ import { CategorizeCashflowTransaction } from './CategorizeCashflowTransaction';
import { import {
CategorizeTransactionAsExpenseDTO, CategorizeTransactionAsExpenseDTO,
CreateUncategorizedTransactionDTO, CreateUncategorizedTransactionDTO,
ICashflowAccountsFilter,
ICashflowNewCommandDTO,
ICategorizeCashflowTransactioDTO, ICategorizeCashflowTransactioDTO,
IUncategorizedCashflowTransaction, IGetUncategorizedTransactionsQuery,
} from '@/interfaces'; } from '@/interfaces';
import { CategorizeTransactionAsExpense } from './CategorizeTransactionAsExpense'; import { CategorizeTransactionAsExpense } from './CategorizeTransactionAsExpense';
import { GetUncategorizedTransactions } from './GetUncategorizedTransactions'; import { GetUncategorizedTransactions } from './GetUncategorizedTransactions';
import { CreateUncategorizedTransaction } from './CreateUncategorizedTransaction'; import { CreateUncategorizedTransaction } from './CreateUncategorizedTransaction';
import { GetUncategorizedTransaction } from './GetUncategorizedTransaction'; import { GetUncategorizedTransaction } from './GetUncategorizedTransaction';
import NewCashflowTransactionService from './NewCashflowTransactionService';
import GetCashflowAccountsService from './GetCashflowAccountsService';
import { GetCashflowTransactionService } from './GetCashflowTransactionsService';
@Service() @Service()
export class CashflowApplication { export class CashflowApplication {
@Inject()
private createTransactionService: NewCashflowTransactionService;
@Inject() @Inject()
private deleteTransactionService: DeleteCashflowTransaction; private deleteTransactionService: DeleteCashflowTransaction;
@Inject()
private getCashflowAccountsService: GetCashflowAccountsService;
@Inject()
private getCashflowTransactionService: GetCashflowTransactionService;
@Inject() @Inject()
private uncategorizeTransactionService: UncategorizeCashflowTransaction; private uncategorizeTransactionService: UncategorizeCashflowTransaction;
@@ -36,6 +50,25 @@ export class CashflowApplication {
@Inject() @Inject()
private createUncategorizedTransactionService: CreateUncategorizedTransaction; private createUncategorizedTransactionService: CreateUncategorizedTransaction;
/**
* Creates a new cashflow transaction.
* @param {number} tenantId
* @param {ICashflowNewCommandDTO} transactionDTO
* @param {number} userId
* @returns
*/
public createTransaction(
tenantId: number,
transactionDTO: ICashflowNewCommandDTO,
userId?: number
) {
return this.createTransactionService.newCashflowTransaction(
tenantId,
transactionDTO,
userId
);
}
/** /**
* Deletes the given cashflow transaction. * Deletes the given cashflow transaction.
* @param {number} tenantId * @param {number} tenantId
@@ -49,6 +82,35 @@ export class CashflowApplication {
); );
} }
/**
* Retrieves specific cashflow transaction.
* @param {number} tenantId
* @param {number} cashflowTransactionId
* @returns
*/
public getTransaction(tenantId: number, cashflowTransactionId: number) {
return this.getCashflowTransactionService.getCashflowTransaction(
tenantId,
cashflowTransactionId
);
}
/**
* Retrieves the cashflow accounts.
* @param {number} tenantId
* @param {ICashflowAccountsFilter} filterDTO
* @returns
*/
public getCashflowAccounts(
tenantId: number,
filterDTO: ICashflowAccountsFilter
) {
return this.getCashflowAccountsService.getCashflowAccounts(
tenantId,
filterDTO
);
}
/** /**
* Creates a new uncategorized cash transaction. * Creates a new uncategorized cash transaction.
* @param {number} tenantId * @param {number} tenantId
@@ -105,7 +167,6 @@ export class CashflowApplication {
* @param {number} tenantId * @param {number} tenantId
* @param {number} cashflowTransactionId * @param {number} cashflowTransactionId
* @param {CategorizeTransactionAsExpenseDTO} transactionDTO * @param {CategorizeTransactionAsExpenseDTO} transactionDTO
* @returns
*/ */
public categorizeAsExpense( public categorizeAsExpense(
tenantId: number, tenantId: number,
@@ -122,20 +183,23 @@ export class CashflowApplication {
/** /**
* Retrieves the uncategorized cashflow transactions. * Retrieves the uncategorized cashflow transactions.
* @param {number} tenantId * @param {number} tenantId
* @returns {}
*/ */
public getUncategorizedTransactions(tenantId: number, accountId: number) { public getUncategorizedTransactions(
tenantId: number,
accountId: number,
query: IGetUncategorizedTransactionsQuery
) {
return this.getUncategorizedTransactionsService.getTransactions( return this.getUncategorizedTransactionsService.getTransactions(
tenantId, tenantId,
accountId accountId,
query
); );
} }
/** /**
* * Retrieves specific uncategorized transaction.
* @param {number} tenantId * @param {number} tenantId
* @param {number} uncategorizedTransactionId * @param {number} uncategorizedTransactionId
* @returns
*/ */
public getUncategorizedTransaction( public getUncategorizedTransaction(
tenantId: number, tenantId: number,

View File

@@ -7,7 +7,7 @@ import { ServiceError } from '@/exceptions';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
@Service() @Service()
export default class GetCashflowTransactionsService { export class GetCashflowTransactionService {
@Inject() @Inject()
private tenancy: HasTenancyService; private tenancy: HasTenancyService;

View File

@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
import HasTenancyService from '../Tenancy/TenancyService'; import HasTenancyService from '../Tenancy/TenancyService';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
import { UncategorizedTransactionTransformer } from './UncategorizedTransactionTransformer'; import { UncategorizedTransactionTransformer } from './UncategorizedTransactionTransformer';
import { IGetUncategorizedTransactionsQuery } from '@/interfaces';
@Service() @Service()
export class GetUncategorizedTransactions { export class GetUncategorizedTransactions {
@@ -16,16 +17,26 @@ export class GetUncategorizedTransactions {
* @param {number} tenantId - Tenant id. * @param {number} tenantId - Tenant id.
* @param {number} accountId - Account Id. * @param {number} accountId - Account Id.
*/ */
public async getTransactions(tenantId: number, accountId: number) { public async getTransactions(
tenantId: number,
accountId: number,
query: IGetUncategorizedTransactionsQuery
) {
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId); const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
// Parsed query with default values.
const _query = {
page: 1,
pageSize: 20,
...query,
};
const { results, pagination } = const { results, pagination } =
await UncategorizedCashflowTransaction.query() await UncategorizedCashflowTransaction.query()
.where('accountId', accountId) .where('accountId', accountId)
.where('categorized', false) .where('categorized', false)
.withGraphFetched('account') .withGraphFetched('account')
.orderBy('date', 'DESC') .orderBy('date', 'DESC')
.pagination(0, 1000); .pagination(_query.page - 1, _query.pageSize);
const data = await this.transformer.transform( const data = await this.transformer.transform(
tenantId, tenantId,