WIP: Allocate landed cost.

This commit is contained in:
a.bouhuolia
2021-07-22 18:11:17 +02:00
parent 1eacc254d8
commit 76c6cb3699
33 changed files with 1577 additions and 163 deletions

View File

@@ -17,11 +17,12 @@ import {
IExpensesService,
ISystemUser,
IPaginationMeta,
IExpenseCategory,
} from 'interfaces';
import DynamicListingService from 'services/DynamicListing/DynamicListService';
import events from 'subscribers/events';
import ContactsService from 'services/Contacts/ContactsService';
import { ACCOUNT_PARENT_TYPE, ACCOUNT_ROOT_TYPE } from 'data/AccountTypes'
import { ACCOUNT_PARENT_TYPE, ACCOUNT_ROOT_TYPE } from 'data/AccountTypes';
const ERRORS = {
EXPENSE_NOT_FOUND: 'expense_not_found',
@@ -32,6 +33,7 @@ const ERRORS = {
PAYMENT_ACCOUNT_HAS_INVALID_TYPE: 'payment_account_has_invalid_type',
EXPENSES_ACCOUNT_HAS_INVALID_TYPE: 'expenses_account_has_invalid_type',
EXPENSE_ALREADY_PUBLISHED: 'expense_already_published',
EXPENSE_HAS_ASSOCIATED_LANDED_COST: 'EXPENSE_HAS_ASSOCIATED_LANDED_COST',
};
@Service()
@@ -308,6 +310,27 @@ export default class ExpensesService implements IExpensesService {
}
}
/**
* Retrieve the expense landed cost amount.
* @param {IExpenseDTO} expenseDTO
* @return {number}
*/
private getExpenseLandedCostAmount(expenseDTO: IExpenseDTO): number {
const landedCostEntries = expenseDTO.categories.filter((entry) => {
return entry.landedCost === true;
});
return this.getExpenseCategoriesTotal(landedCostEntries);
}
/**
* Retrieve the given expense categories total.
* @param {IExpenseCategory} categories
* @returns {number}
*/
private getExpenseCategoriesTotal(categories): number {
return sumBy(categories, 'amount');
}
/**
* Mapping expense DTO to model.
* @param {IExpenseDTO} expenseDTO
@@ -315,12 +338,14 @@ export default class ExpensesService implements IExpensesService {
* @return {IExpense}
*/
private expenseDTOToModel(expenseDTO: IExpenseDTO, user?: ISystemUser) {
const totalAmount = sumBy(expenseDTO.categories, 'amount');
const landedCostAmount = this.getExpenseLandedCostAmount(expenseDTO);
const totalAmount = this.getExpenseCategoriesTotal(expenseDTO.categories);
return {
categories: [],
...omit(expenseDTO, ['publish']),
totalAmount,
landedCostAmount,
paymentDate: moment(expenseDTO.paymentDate).toMySqlDateTime(),
...(user
? {
@@ -340,7 +365,7 @@ export default class ExpensesService implements IExpensesService {
* @param {IExpenseDTO} expenseDTO
* @return {number[]}
*/
mapExpensesAccountsIdsFromDTO(expenseDTO: IExpenseDTO) {
private mapExpensesAccountsIdsFromDTO(expenseDTO: IExpenseDTO) {
return expenseDTO.categories.map((category) => category.expenseAccountId);
}
@@ -544,15 +569,16 @@ export default class ExpensesService implements IExpensesService {
authorizedUser: ISystemUser
): Promise<void> {
const oldExpense = await this.getExpenseOrThrowError(tenantId, expenseId);
const {
expenseRepository,
expenseEntryRepository,
} = this.tenancy.repositories(tenantId);
const { expenseRepository, expenseEntryRepository } =
this.tenancy.repositories(tenantId);
this.logger.info('[expense] trying to delete the expense.', {
tenantId,
expenseId,
});
// Validates the expense has no associated landed cost.
await this.validateNoAssociatedLandedCost(tenantId, expenseId);
await expenseEntryRepository.deleteBy({ expenseId });
await expenseRepository.deleteById(expenseId);
@@ -572,7 +598,7 @@ export default class ExpensesService implements IExpensesService {
/**
* Filters the not published expenses.
* @param {IExpense[]} expenses -
* @param {IExpense[]} expenses -
*/
public getNonePublishedExpenses(expenses: IExpense[]): IExpense[] {
return expenses.filter((expense) => !expense.publishedAt);
@@ -648,4 +674,25 @@ export default class ExpensesService implements IExpensesService {
}
return expense;
}
/**
* Validates the expense has not associated landed cost
* references to the given expense.
* @param {number} tenantId
* @param {number} expenseId
*/
public async validateNoAssociatedLandedCost(
tenantId: number,
expenseId: number
) {
const { BillLandedCost } = this.tenancy.models(tenantId);
const associatedLandedCosts = await BillLandedCost.query()
.where('fromTransactionType', 'Expense')
.where('fromTransactionId', expenseId);
if (associatedLandedCosts.length > 0) {
throw new ServiceError(ERRORS.EXPENSE_HAS_ASSOCIATED_LANDED_COST);
}
}
}