mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 21:00:31 +00:00
fix: database migrations FK relations.
fix: database columns indexing.
This commit is contained in:
@@ -2,9 +2,12 @@ import { sumBy, chain } from 'lodash';
|
||||
import JournalPoster from "./JournalPoster";
|
||||
import JournalEntry from "./JournalEntry";
|
||||
import { AccountTransaction } from 'models';
|
||||
import { IInventoryTransaction, IManualJournal } from 'interfaces';
|
||||
import AccountsService from '../Accounts/AccountsService';
|
||||
import { IInventoryTransaction, IInventoryTransaction } from '../../interfaces';
|
||||
import {
|
||||
IInventoryTransaction,
|
||||
IManualJournal,
|
||||
IExpense,
|
||||
IExpenseCategory,
|
||||
} from 'interfaces';
|
||||
|
||||
interface IInventoryCostEntity {
|
||||
date: Date,
|
||||
@@ -120,6 +123,36 @@ export default class JournalCommands{
|
||||
this.journal.credit(creditEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes journal entries of expense model object.
|
||||
* @param {IExpense} expense
|
||||
*/
|
||||
expense(expense: IExpense) {
|
||||
const mixinEntry = {
|
||||
referenceType: 'Expense',
|
||||
referenceId: expense.id,
|
||||
date: expense.paymentDate,
|
||||
userId: expense.userId,
|
||||
draft: !expense.publishedAt,
|
||||
};
|
||||
const paymentJournalEntry = new JournalEntry({
|
||||
credit: expense.totalAmount,
|
||||
account: expense.paymentAccountId,
|
||||
...mixinEntry,
|
||||
});
|
||||
this.journal.credit(paymentJournalEntry);
|
||||
|
||||
expense.categories.forEach((category: IExpenseCategory) => {
|
||||
const expenseJournalEntry = new JournalEntry({
|
||||
account: category.expenseAccountId,
|
||||
debit: category.amount,
|
||||
note: category.description,
|
||||
...mixinEntry,
|
||||
});
|
||||
this.journal.debit(expenseJournalEntry);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number|number[]} referenceId
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { difference } from 'lodash';
|
||||
import { kebabCase } from 'lodash'
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { ServiceError } from 'exceptions';
|
||||
import { IAccountDTO, IAccount, IAccountsFilter } from 'interfaces';
|
||||
import { difference } from 'lodash';
|
||||
import {
|
||||
EventDispatcher,
|
||||
EventDispatcherInterface,
|
||||
} from 'decorators/eventDispatcher';
|
||||
import DynamicListingService from 'services/DynamicListing/DynamicListService';
|
||||
import events from 'subscribers/events';
|
||||
|
||||
@Service()
|
||||
export default class AccountsService {
|
||||
@@ -17,6 +22,9 @@ export default class AccountsService {
|
||||
@Inject('logger')
|
||||
logger: any;
|
||||
|
||||
@EventDispatcher()
|
||||
eventDispatcher: EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Retrieve account type or throws service error.
|
||||
* @param {number} tenantId -
|
||||
@@ -104,10 +112,10 @@ export default class AccountsService {
|
||||
* @return {IAccount}
|
||||
*/
|
||||
private async getAccountOrThrowError(tenantId: number, accountId: number) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
this.logger.info('[accounts] validating the account existance.', { tenantId, accountId });
|
||||
const account = await Account.query().findById(accountId);
|
||||
const account = await accountRepository.findById(accountId);
|
||||
|
||||
if (!account) {
|
||||
this.logger.info('[accounts] the given account not found.', { accountId });
|
||||
@@ -159,8 +167,8 @@ export default class AccountsService {
|
||||
* @returns {IAccount}
|
||||
*/
|
||||
public async newAccount(tenantId: number, accountDTO: IAccountDTO) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
// Validate account name uniquiness.
|
||||
await this.validateAccountNameUniquiness(tenantId, accountDTO.name);
|
||||
|
||||
@@ -176,11 +184,15 @@ export default class AccountsService {
|
||||
);
|
||||
this.throwErrorIfParentHasDiffType(accountDTO, parentAccount);
|
||||
}
|
||||
const account = await Account.query().insertAndFetch({
|
||||
const account = await accountRepository.insert({
|
||||
...accountDTO,
|
||||
slug: kebabCase(accountDTO.name),
|
||||
});
|
||||
this.logger.info('[account] account created successfully.', { account, accountDTO });
|
||||
|
||||
// Triggers `onAccountCreated` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onCreated);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
@@ -191,7 +203,7 @@ export default class AccountsService {
|
||||
* @param {IAccountDTO} accountDTO
|
||||
*/
|
||||
public async editAccount(tenantId: number, accountId: number, accountDTO: IAccountDTO) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
const oldAccount = await this.getAccountOrThrowError(tenantId, accountId);
|
||||
|
||||
// Validate account name uniquiness.
|
||||
@@ -214,12 +226,13 @@ export default class AccountsService {
|
||||
this.throwErrorIfParentHasDiffType(accountDTO, parentAccount);
|
||||
}
|
||||
// Update the account on the storage.
|
||||
const account = await Account.query().patchAndFetchById(
|
||||
oldAccount.id, { ...accountDTO }
|
||||
);
|
||||
const account = await accountRepository.edit(oldAccount.id, accountDTO);
|
||||
this.logger.info('[account] account edited successfully.', {
|
||||
account, accountDTO, tenantId
|
||||
});
|
||||
// Triggers `onAccountEdited` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onEdited);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
@@ -309,7 +322,7 @@ export default class AccountsService {
|
||||
* @param {number} accountId
|
||||
*/
|
||||
public async deleteAccount(tenantId: number, accountId: number) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
const account = await this.getAccountOrThrowError(tenantId, accountId);
|
||||
|
||||
this.throwErrorIfAccountPredefined(account);
|
||||
@@ -317,10 +330,13 @@ export default class AccountsService {
|
||||
await this.throwErrorIfAccountHasChildren(tenantId, accountId);
|
||||
await this.throwErrorIfAccountHasTransactions(tenantId, accountId);
|
||||
|
||||
await Account.query().deleteById(account.id);
|
||||
await accountRepository.deleteById(account.id);
|
||||
this.logger.info('[account] account has been deleted successfully.', {
|
||||
tenantId, accountId,
|
||||
})
|
||||
});
|
||||
|
||||
// Triggers `onAccountDeleted` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onDeleted);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,6 +416,9 @@ export default class AccountsService {
|
||||
this.logger.info('[account] given accounts deleted in bulk successfully.', {
|
||||
tenantId, accountsIds
|
||||
});
|
||||
|
||||
// Triggers `onBulkDeleted` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onBulkDeleted);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,6 +437,9 @@ export default class AccountsService {
|
||||
active: activate ? 1 : 0,
|
||||
});
|
||||
this.logger.info('[account] accounts have been activated successfully.', { tenantId, accountsIds });
|
||||
|
||||
// Triggers `onAccountBulkActivated` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onActivated);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -436,6 +458,9 @@ export default class AccountsService {
|
||||
active: activate ? 1 : 0,
|
||||
})
|
||||
this.logger.info('[account] account have been activated successfully.', { tenantId, accountId });
|
||||
|
||||
// Triggers `onAccountActivated` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onActivated);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,12 +7,13 @@ import {
|
||||
EventDispatcher,
|
||||
EventDispatcherInterface,
|
||||
} from 'decorators/eventDispatcher';
|
||||
import { SystemUser, PasswordReset } from 'system/models';
|
||||
import { PasswordReset } from 'system/models';
|
||||
import {
|
||||
IRegisterDTO,
|
||||
ITenant,
|
||||
ISystemUser,
|
||||
IPasswordReset,
|
||||
IAuthenticationService,
|
||||
} from 'interfaces';
|
||||
import { hashPassword } from 'utils';
|
||||
import { ServiceError, ServiceErrors } from 'exceptions';
|
||||
|
||||
@@ -45,10 +45,10 @@ export default class ContactsService {
|
||||
* @param {IContactDTO} contactDTO
|
||||
*/
|
||||
async newContact(tenantId: number, contactDTO: IContactNewDTO, contactService: TContactService) {
|
||||
const { Contact } = this.tenancy.models(tenantId);
|
||||
const { contactRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
this.logger.info('[contacts] trying to insert contact to the storage.', { tenantId, contactDTO });
|
||||
const contact = await Contact.query().insert({ contactService, ...contactDTO });
|
||||
const contact = await contactRepository.insert({ contactService, ...contactDTO });
|
||||
|
||||
this.logger.info('[contacts] contact inserted successfully.', { tenantId, contact });
|
||||
return contact;
|
||||
@@ -77,11 +77,11 @@ export default class ContactsService {
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async deleteContact(tenantId: number, contactId: number, contactService: TContactService) {
|
||||
const { Contact } = this.tenancy.models(tenantId);
|
||||
const { contactRepository } = this.tenancy.repositories(tenantId);
|
||||
const contact = await this.getContactByIdOrThrowError(tenantId, contactId, contactService);
|
||||
|
||||
this.logger.info('[contacts] trying to delete the given contact.', { tenantId, contactId });
|
||||
await Contact.query().findById(contactId).delete();
|
||||
await contactRepository.deleteById(contactId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,10 +124,10 @@ export default class ContactsService {
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async deleteBulkContacts(tenantId: number, contactsIds: number[], contactService: TContactService) {
|
||||
const { Contact } = this.tenancy.models(tenantId);
|
||||
const { contactRepository } = this.tenancy.repositories(tenantId);
|
||||
this.getContactsOrThrowErrorNotFound(tenantId, contactsIds, contactService);
|
||||
|
||||
await Contact.query().whereIn('id', contactsIds).delete();
|
||||
await contactRepository.bulkDelete(contactsIds);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,10 +6,10 @@ import ContactsService from 'services/Contacts/ContactsService';
|
||||
import {
|
||||
ICustomerNewDTO,
|
||||
ICustomerEditDTO,
|
||||
ICustomer,
|
||||
} from 'interfaces';
|
||||
import { ServiceError } from 'exceptions';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { ICustomer } from 'src/interfaces';
|
||||
|
||||
@Service()
|
||||
export default class CustomersService {
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
import Resource from 'models/Resource';
|
||||
import ResourceField from 'models/ResourceField';
|
||||
import ResourceFieldMetadata from 'models/ResourceFieldMetadata';
|
||||
import ResourceFieldMetadataCollection from 'collection/ResourceFieldMetadataCollection';
|
||||
|
||||
export default class ResourceCustomFieldRepository {
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
constructor(model) {
|
||||
if (typeof model === 'function') {
|
||||
this.resourceName = model.name;
|
||||
} else if (typeof model === 'string') {
|
||||
this.resourceName = model;
|
||||
}
|
||||
// Custom fields of the given resource.
|
||||
this.customFields = [];
|
||||
this.filledCustomFields = {};
|
||||
|
||||
// metadata of custom fields of the given resource.
|
||||
this.fieldsMetadata = {};
|
||||
this.resource = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches metadata of custom fields of the given resource.
|
||||
* @param {Integer} id - Resource item id.
|
||||
*/
|
||||
async fetchCustomFieldsMetadata(id) {
|
||||
if (typeof id === 'undefined') {
|
||||
throw new Error('Please define the resource item id.');
|
||||
}
|
||||
if (!this.resource) {
|
||||
throw new Error('Target resource model is not found.');
|
||||
}
|
||||
const metadata = await ResourceFieldMetadata.query()
|
||||
.where('resource_id', this.resource.id)
|
||||
.where('resource_item_id', id);
|
||||
|
||||
this.fieldsMetadata[id] = metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load resource.
|
||||
*/
|
||||
async loadResource() {
|
||||
const resource = await Resource.query().where('name', this.resourceName).first();
|
||||
|
||||
if (!resource) {
|
||||
throw new Error('There is no stored resource in the storage with the given model name.');
|
||||
}
|
||||
this.setResource(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load metadata of the resource.
|
||||
*/
|
||||
async loadResourceCustomFields() {
|
||||
if (typeof this.resource.id === 'undefined') {
|
||||
throw new Error('Please fetch resource details before fetch custom fields of the resource.');
|
||||
}
|
||||
const customFields = await ResourceField.query()
|
||||
.where('resource_id', this.resource.id)
|
||||
.modify('whereNotPredefined');
|
||||
|
||||
this.setResourceCustomFields(customFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets resource model.
|
||||
* @param {Resource} resource -
|
||||
*/
|
||||
setResource(resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets resource custom fields collection.
|
||||
* @param {Array} customFields -
|
||||
*/
|
||||
setResourceCustomFields(customFields) {
|
||||
this.customFields = customFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve metadata of the resource custom fields.
|
||||
* @param {Integer} itemId -
|
||||
*/
|
||||
getMetadata(itemId) {
|
||||
return this.fieldsMetadata[itemId] || this.fieldsMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill metadata of the custom fields that associated to the resource.
|
||||
* @param {Inter} id - Resource item id.
|
||||
* @param {Array} attributes -
|
||||
*/
|
||||
fillCustomFields(id, attributes) {
|
||||
if (typeof this.filledCustomFields[id] === 'undefined') {
|
||||
this.filledCustomFields[id] = [];
|
||||
}
|
||||
attributes.forEach((attr) => {
|
||||
this.filledCustomFields[id].push(attr);
|
||||
|
||||
if (!this.fieldsMetadata[id]) {
|
||||
this.fieldsMetadata[id] = new ResourceFieldMetadataCollection();
|
||||
}
|
||||
this.fieldsMetadata[id].setMeta(attr.key, attr.value, {
|
||||
resource_id: this.resource.id,
|
||||
resource_item_id: id,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the instered, updated and deleted custom fields metadata.
|
||||
* @param {Integer} id - Optional resource item id.
|
||||
*/
|
||||
async saveCustomFields(id) {
|
||||
if (id) {
|
||||
if (typeof this.fieldsMetadata[id] === 'undefined') {
|
||||
throw new Error('There is no resource item with the given id.');
|
||||
}
|
||||
await this.fieldsMetadata[id].saveMeta();
|
||||
} else {
|
||||
const opers = [];
|
||||
this.fieldsMetadata.forEach((metadata) => {
|
||||
const oper = metadata.saveMeta();
|
||||
opers.push(oper);
|
||||
});
|
||||
await Promise.all(opers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the exist custom fields.
|
||||
*/
|
||||
validateExistCustomFields() {
|
||||
|
||||
}
|
||||
|
||||
toArray() {
|
||||
return this.fieldsMetadata.toArray();
|
||||
}
|
||||
|
||||
async load() {
|
||||
await this.loadResource();
|
||||
await this.loadResourceCustomFields();
|
||||
}
|
||||
|
||||
static forgeMetadataCollection() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ export default class DynamicListService implements IDynamicListService {
|
||||
this.validateFilterRolesSchema(filter.filterRoles);
|
||||
this.validateRolesFieldsExistance(model, filter.filterRoles);
|
||||
|
||||
// Validate the accounts resource fields.
|
||||
// Validate the model resource fields.
|
||||
const filterRoles = new DynamicFilterFilterRoles(filter.filterRoles);
|
||||
dynamicFilter.setFilter(filterRoles);
|
||||
}
|
||||
|
||||
@@ -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