feat: Add transactions by given reference report.

This commit is contained in:
a.bouhuolia
2021-08-01 11:36:03 +02:00
parent 3546b6b7ae
commit 64c4965451
7 changed files with 309 additions and 0 deletions

View File

@@ -17,6 +17,7 @@ import TransactionsByCustomers from './FinancialStatements/TransactionsByCustome
import TransactionsByVendors from './FinancialStatements/TransactionsByVendors';
import CashFlowStatementController from './FinancialStatements/CashFlow/CashFlow';
import InventoryDetailsController from './FinancialStatements/InventoryDetails';
import TransactionsByReferenceController from './FinancialStatements/TransactionsByReference';
@Service()
export default class FinancialStatementsService {
@@ -87,6 +88,10 @@ export default class FinancialStatementsService {
'/inventory-item-details',
Container.get(InventoryDetailsController).router(),
);
router.use(
'/transactions-by-reference',
Container.get(TransactionsByReferenceController).router(),
)
return router;
}
}

View File

@@ -0,0 +1,87 @@
import { Inject, Service } from 'typedi';
import { Router, Request, Response, NextFunction } from 'express';
import { query, ValidationChain } from 'express-validator';
import BaseController from 'api/controllers/BaseController';
import TransactionsByReferenceService from 'services/FinancialStatements/TransactionsByReference';
@Service()
export default class TransactionsByReferenceController extends BaseController {
@Inject()
private transactionsByReferenceService: TransactionsByReferenceService;
/**
* Router constructor.
*/
router() {
const router = Router();
router.get(
'/',
this.validationSchema,
this.validationResult,
this.asyncMiddleware(this.transactionsByReference.bind(this))
);
return router;
}
/**
* Validation schema.
*/
get validationSchema(): ValidationChain[] {
return [
query('reference_id').exists().isInt(),
query('reference_type').exists().isString(),
query('number_format.precision')
.optional()
.isInt({ min: 0, max: 5 })
.toInt(),
query('number_format.divide_on_1000').optional().isBoolean().toBoolean(),
query('number_format.negative_format')
.optional()
.isIn(['parentheses', 'mines'])
.trim()
.escape(),
];
}
/**
* Retrieve transactions by the given reference type and id.
* @param {Request} req - Request object.
* @param {Response} res - Response.
* @param {NextFunction} next
* @returns
*/
public async transactionsByReference(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
const filter = this.matchedQueryData(req);
try {
const transactions =
await this.transactionsByReferenceService.getTransactionsByReference(
tenantId,
filter
);
const accept = this.accepts(req);
const acceptType = accept.types(['json']);
switch (acceptType) {
case 'json':
default:
return res
.status(200)
.send(this.transformToJsonResponse(transactions));
}
} catch (error) {
next(error);
}
}
private transformToJsonResponse(transactions) {
return transactions;
}
}

View File

@@ -0,0 +1,31 @@
export interface ITransactionsByReferenceQuery {
referenceType: string;
referenceId: string;
}
export interface ITransactionsByReferenceAmount {
amount: number;
formattedAmount: string;
currencyCode: string;
}
export interface ITransactionsByReferenceTransaction{
credit: ITransactionsByReferenceAmount;
debit: ITransactionsByReferenceAmount;
contactType: string;
formattedContactType: string;
contactId: number;
referenceType: string;
formattedReferenceType: string;
referenceId: number;
accountName: string;
accountCode: string;
accountId: number;
}

View File

@@ -55,6 +55,7 @@ export * from './CashFlow';
export * from './InventoryDetails';
export * from './LandedCost';
export * from './Entry';
export * from './TransactionsByReference';
export interface I18nService {
__: (input: string) => string;

View File

@@ -0,0 +1,79 @@
import {
IAccount,
IAccountTransaction,
INumberFormatQuery,
ITransactionsByReferenceQuery,
ITransactionsByReferenceTransaction,
} from 'interfaces';
import FinancialSheet from '../FinancialSheet';
export default class TransactionsByReference extends FinancialSheet {
readonly transactions: IAccountTransaction[];
readonly query: ITransactionsByReferenceQuery;
readonly baseCurrency: string;
readonly numberFormat: INumberFormatQuery;
/**
* Constructor method.
* @param {IAccountTransaction[]} transactions
* @param {ITransactionsByReferenceQuery} query
* @param {string} baseCurrency
*/
constructor(
transactions: (IAccountTransaction & { account: IAccount }) [],
query: ITransactionsByReferenceQuery,
baseCurrency: string
) {
super();
this.transactions = transactions;
this.query = query;
this.baseCurrency = baseCurrency;
this.numberFormat = this.query.numberFormat;
}
/**
* Mappes the given account transaction to report transaction.
* @param {IAccountTransaction} transaction
* @returns {ITransactionsByReferenceTransaction}
*/
private transactionMapper = (
transaction: IAccountTransaction
): ITransactionsByReferenceTransaction => {
return {
credit: this.getAmountMeta(transaction.credit, { money: true }),
debit: this.getAmountMeta(transaction.debit, { money: true }),
referenceTypeFormatted: transaction.referenceTypeFormatted,
referenceType: transaction.referenceType,
referenceId: transaction.referenceId,
contactId: transaction.contactId,
contactType: transaction.contactType,
contactTypeFormatted: transaction.contactType,
accountName: transaction.account.name,
accountCode: transaction.account.code,
accountId: transaction.accountId,
};
};
/**
* Mappes the given accounts transactions to report transactions.
* @param {IAccountTransaction} transaction
* @returns {ITransactionsByReferenceTransaction}
*/
private transactionsMapper = (
transactions: IAccountTransaction[]
): ITransactionsByReferenceTransaction[] => {
return transactions.map(this.transactionMapper);
};
/**
* Retrieve the report data.
* @returns {ITransactionsByReferenceTransaction}
*/
public reportData(): ITransactionsByReferenceTransaction[] {
return this.transactionsMapper(this.transactions);
}
}

View File

@@ -0,0 +1,29 @@
import HasTenancyService from 'services/Tenancy/TenancyService';
import { Service, Inject } from 'typedi';
import { IAccount, IAccountTransaction, ITransactionsByReferenceQuery } from 'interfaces';
@Service()
export default class TransactionsByReferenceRepository {
@Inject()
tenancy: HasTenancyService;
/**
* Retrieve the accounts transactions of the givne reference id and type.
* @param {number} tenantId -
* @param {number} referenceId - Reference id.
* @param {string} referenceType - Reference type.
* @return {Promise<IAccountTransaction[]>}
*/
public getTransactions(
tenantId: number,
referenceId: number,
referenceType: string,
): Promise<(IAccountTransaction & { account: IAccount }) []> {
const { AccountTransaction } = this.tenancy.models(tenantId);
return AccountTransaction.query()
.where('reference_id', referenceId)
.where('reference_type', referenceType)
.withGraphFetched('account');
}
}

View File

@@ -0,0 +1,77 @@
import { Service, Inject } from 'typedi';
import HasTenancyService from 'services/Tenancy/TenancyService';
import {
ITransactionsByReferenceQuery,
ITransactionsByReferenceTransaction,
} from 'interfaces';
import TransactionsByReferenceRepository from './TransactionsByReferenceRepository';
import TransactionsByReferenceReport from './TransactionsByReferenceReport';
@Service()
export default class TransactionsByReferenceService {
@Inject()
tenancy: HasTenancyService;
@Inject('logger')
logger: any;
@Inject()
reportRepository: TransactionsByReferenceRepository;
/**
* Default query of transactions by reference report.
*/
get defaultQuery(): ITransactionsByReferenceQuery {
return {
numberFormat: {
precision: 2,
divideOn1000: false,
showZero: false,
formatMoney: 'total',
negativeFormat: 'mines',
},
};
}
/**
* Retrieve accounts transactions by given reference id and type.
* @param {number} tenantId
* @param {ITransactionsByReferenceQuery} filter
*/
public async getTransactionsByReference(
tenantId: number,
query: ITransactionsByReferenceQuery
): Promise<{
data: ITransactionsByReferenceTransaction[];
}> {
const filter = {
...this.defaultQuery,
...query,
};
// Retrieve the accounts transactions of the given reference.
const transactions = await this.reportRepository.getTransactions(
tenantId,
filter.referenceId,
filter.referenceType
);
// Settings tenant service.
const settings = this.tenancy.settings(tenantId);
const baseCurrency = settings.get({
group: 'organization',
key: 'base_currency',
});
// Transactions by reference report.
const report = new TransactionsByReferenceReport(
transactions,
filter,
baseCurrency
);
return {
data: report.reportData(),
};
}
}