mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
fix: database migrations FK relations.
fix: database columns indexing.
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
import { Service, Inject } from "typedi";
|
||||
import { difference, sumBy, omit } from 'lodash';
|
||||
import moment from "moment";
|
||||
import {
|
||||
EventDispatcher,
|
||||
EventDispatcherInterface,
|
||||
} from 'decorators/eventDispatcher';
|
||||
import { ServiceError } from "exceptions";
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import JournalPoster from 'services/Accounting/JournalPoster';
|
||||
import JournalEntry from 'services/Accounting/JournalEntry';
|
||||
import JournalCommands from 'services/Accounting/JournalCommands';
|
||||
import { IExpense, IAccount, IExpenseDTO, IExpenseCategory, IExpensesService, ISystemUser } from 'interfaces';
|
||||
import { IExpense, IAccount, IExpenseDTO, IExpensesService, ISystemUser } from 'interfaces';
|
||||
import DynamicListingService from 'services/DynamicListing/DynamicListService';
|
||||
import events from 'subscribers/events';
|
||||
|
||||
const ERRORS = {
|
||||
EXPENSE_NOT_FOUND: 'expense_not_found',
|
||||
@@ -30,6 +34,9 @@ export default class ExpensesService implements IExpensesService {
|
||||
@Inject('logger')
|
||||
logger: any;
|
||||
|
||||
@EventDispatcher()
|
||||
eventDispatcher: EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Retrieve the payment account details or returns not found server error in case the
|
||||
* given account not found on the storage.
|
||||
@@ -158,11 +165,10 @@ export default class ExpensesService implements IExpensesService {
|
||||
* @param {IExpense} expense
|
||||
* @param {IUser} authorizedUser
|
||||
*/
|
||||
private async writeJournalEntries(
|
||||
public async writeJournalEntries(
|
||||
tenantId: number,
|
||||
expense: IExpense,
|
||||
revertOld: boolean,
|
||||
authorizedUser: ISystemUser
|
||||
) {
|
||||
this.logger.info('[expense[ trying to write expense journal entries.', { tenantId, expense });
|
||||
const journal = new JournalPoster(tenantId);
|
||||
@@ -171,29 +177,8 @@ export default class ExpensesService implements IExpensesService {
|
||||
if (revertOld) {
|
||||
await journalCommands.revertJournalEntries(expense.id, 'Expense');
|
||||
}
|
||||
const mixinEntry = {
|
||||
referenceType: 'Expense',
|
||||
referenceId: expense.id,
|
||||
date: expense.paymentDate,
|
||||
userId: authorizedUser.id,
|
||||
draft: !expense.publish,
|
||||
};
|
||||
const paymentJournalEntry = new JournalEntry({
|
||||
credit: expense.totalAmount,
|
||||
account: expense.paymentAccountId,
|
||||
...mixinEntry,
|
||||
});
|
||||
journal.credit(paymentJournalEntry);
|
||||
|
||||
expense.categories.forEach((category: IExpenseCategory) => {
|
||||
const expenseJournalEntry = new JournalEntry({
|
||||
account: category.expenseAccountId,
|
||||
debit: category.amount,
|
||||
note: category.description,
|
||||
...mixinEntry,
|
||||
});
|
||||
journal.debit(expenseJournalEntry);
|
||||
});
|
||||
journalCommands.expense(expense);
|
||||
|
||||
return Promise.all([
|
||||
journal.saveBalance(),
|
||||
journal.saveEntries(),
|
||||
@@ -229,7 +214,7 @@ export default class ExpensesService implements IExpensesService {
|
||||
* @param {IExpense} expense
|
||||
*/
|
||||
private validateExpenseIsNotPublished(expense: IExpense) {
|
||||
if (expense.published) {
|
||||
if (expense.publishedAt) {
|
||||
throw new ServiceError(ERRORS.EXPENSE_ACCOUNT_ALREADY_PUBLISED);
|
||||
}
|
||||
}
|
||||
@@ -291,33 +276,29 @@ export default class ExpensesService implements IExpensesService {
|
||||
const { expenseRepository } = this.tenancy.repositories(tenantId);
|
||||
const expense = await this.getExpenseOrThrowError(tenantId, expenseId);
|
||||
|
||||
// 1. Validate payment account existance on the storage.
|
||||
// - Validate payment account existance on the storage.
|
||||
const paymentAccount = await this.getPaymentAccountOrThrowError(
|
||||
tenantId,
|
||||
expenseDTO.paymentAccountId,
|
||||
);
|
||||
// 2. Validate expense accounts exist on the storage.
|
||||
// - Validate expense accounts exist on the storage.
|
||||
const expensesAccounts = await this.getExpensesAccountsOrThrowError(
|
||||
tenantId,
|
||||
this.mapExpensesAccountsIdsFromDTO(expenseDTO),
|
||||
);
|
||||
// 3. Validate payment account type.
|
||||
// - Validate payment account type.
|
||||
await this.validatePaymentAccountType(tenantId, paymentAccount);
|
||||
|
||||
// 4. Validate expenses accounts type.
|
||||
// - Validate expenses accounts type.
|
||||
await this.validateExpensesAccountsType(tenantId, expensesAccounts);
|
||||
|
||||
// 5. Validate the given expense categories not equal zero.
|
||||
// - Validate the given expense categories not equal zero.
|
||||
this.validateCategoriesNotEqualZero(expenseDTO);
|
||||
|
||||
// 6. Update the expense on the storage.
|
||||
// - Update the expense on the storage.
|
||||
const expenseObj = this.expenseDTOToModel(expenseDTO);
|
||||
const expenseModel = await expenseRepository.update(expenseId, expenseObj, null);
|
||||
|
||||
// 7. In case expense published, write journal entries.
|
||||
if (expenseObj.published) {
|
||||
await this.writeJournalEntries(tenantId, expenseModel, true, authorizedUser);
|
||||
}
|
||||
this.logger.info('[expense] the expense updated on the storage successfully.', { tenantId, expenseDTO });
|
||||
return expenseModel;
|
||||
}
|
||||
@@ -364,13 +345,12 @@ export default class ExpensesService implements IExpensesService {
|
||||
// 6. Save the expense to the storage.
|
||||
const expenseObj = this.expenseDTOToModel(expenseDTO, authorizedUser);
|
||||
const expenseModel = await expenseRepository.create(expenseObj);
|
||||
|
||||
// 7. In case expense published, write journal entries.
|
||||
if (expenseObj.published) {
|
||||
await this.writeJournalEntries(tenantId, expenseModel, false, authorizedUser);
|
||||
}
|
||||
|
||||
this.logger.info('[expense] the expense stored to the storage successfully.', { tenantId, expenseDTO });
|
||||
|
||||
// Triggers `onExpenseCreated` event.
|
||||
this.eventDispatcher.dispatch(events.expenses.onCreated, { tenantId, expenseId: expenseModel.id });
|
||||
|
||||
return expenseModel;
|
||||
}
|
||||
|
||||
@@ -394,6 +374,9 @@ export default class ExpensesService implements IExpensesService {
|
||||
await expenseRepository.publish(expenseId);
|
||||
|
||||
this.logger.info('[expense] the expense published successfully.', { tenantId, expenseId });
|
||||
|
||||
// Triggers `onExpensePublished` event.
|
||||
this.eventDispatcher.dispatch(events.expenses.onPublished, { tenantId, expenseId });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,10 +392,10 @@ export default class ExpensesService implements IExpensesService {
|
||||
this.logger.info('[expense] trying to delete the expense.', { tenantId, expenseId });
|
||||
await expenseRepository.delete(expenseId);
|
||||
|
||||
if (expense.published) {
|
||||
await this.revertJournalEntries(tenantId, expenseId);
|
||||
}
|
||||
this.logger.info('[expense] the expense deleted successfully.', { tenantId, expenseId });
|
||||
|
||||
// Triggers `onExpenseDeleted` event.
|
||||
this.eventDispatcher.dispatch(events.expenses.onDeleted, { tenantId, expenseId });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,9 +410,11 @@ export default class ExpensesService implements IExpensesService {
|
||||
|
||||
this.logger.info('[expense] trying to delete the given expenses.', { tenantId, expensesIds });
|
||||
await expenseRepository.bulkDelete(expensesIds);
|
||||
await this.revertJournalEntries(tenantId, expensesIds);
|
||||
|
||||
this.logger.info('[expense] the given expenses deleted successfully.', { tenantId, expensesIds });
|
||||
|
||||
// Triggers `onExpenseBulkDeleted` event.
|
||||
this.eventDispatcher.dispatch(events.expenses.onBulkDeleted, { tenantId, expensesIds });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -443,9 +428,12 @@ export default class ExpensesService implements IExpensesService {
|
||||
const { expenseRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
this.logger.info('[expense] trying to publish the given expenses.', { tenantId, expensesIds });
|
||||
await expenseRepository.publishBulk(expensesIds);
|
||||
await expenseRepository.bulkPublish(expensesIds);
|
||||
|
||||
this.logger.info('[expense] the given expenses ids published successfully.', { tenantId, expensesIds });
|
||||
|
||||
// Triggers `onExpenseBulkDeleted` event.
|
||||
this.eventDispatcher.dispatch(events.expenses.onBulkPublished, { tenantId, expensesIds });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user