Files
bigcapital/server/src/services/Contacts/ContactsService.ts
Ahmed Bouhuolia 0114ed9f8b fix: database migrations FK relations.
fix: database columns indexing.
2020-10-03 12:08:11 +02:00

159 lines
5.5 KiB
TypeScript

import { Inject, Service } from 'typedi';
import { difference, upperFirst } from 'lodash';
import { ServiceError } from "exceptions";
import TenancyService from 'services/Tenancy/TenancyService';
import {
IContact,
IContactNewDTO,
IContactEditDTO,
} from "interfaces";
import JournalPoster from '../Accounting/JournalPoster';
type TContactService = 'customer' | 'vendor';
@Service()
export default class ContactsService {
@Inject()
tenancy: TenancyService;
@Inject('logger')
logger: any;
/**
* Get the given contact or throw not found contact.
* @param {number} tenantId
* @param {number} contactId
* @param {TContactService} contactService
* @return {Promise<IContact>}
*/
private async getContactByIdOrThrowError(tenantId: number, contactId: number, contactService: TContactService) {
const { Contact } = this.tenancy.models(tenantId);
this.logger.info('[contact] trying to validate contact existance.', { tenantId, contactId });
const contact = await Contact.query().findById(contactId).where('contact_service', contactService);
if (!contact) {
throw new ServiceError('contact_not_found');
}
return contact;
}
/**
* Creates a new contact on the storage.
* @param {number} tenantId
* @param {TContactService} contactService
* @param {IContactDTO} contactDTO
*/
async newContact(tenantId: number, contactDTO: IContactNewDTO, contactService: TContactService) {
const { contactRepository } = this.tenancy.repositories(tenantId);
this.logger.info('[contacts] trying to insert contact to the storage.', { tenantId, contactDTO });
const contact = await contactRepository.insert({ contactService, ...contactDTO });
this.logger.info('[contacts] contact inserted successfully.', { tenantId, contact });
return contact;
}
/**
* Edit details of the given on the storage.
* @param {number} tenantId
* @param {number} contactId
* @param {TContactService} contactService
* @param {IContactDTO} contactDTO
*/
async editContact(tenantId: number, contactId: number, contactDTO: IContactEditDTO, contactService: TContactService) {
const { Contact } = this.tenancy.models(tenantId);
const contact = await this.getContactByIdOrThrowError(tenantId, contactId, contactService);
this.logger.info('[contacts] trying to edit the given contact details.', { tenantId, contactId, contactDTO });
await Contact.query().findById(contactId).patch({ ...contactDTO })
}
/**
* Deletes the given contact from the storage.
* @param {number} tenantId
* @param {number} contactId
* @param {TContactService} contactService
* @return {Promise<void>}
*/
async deleteContact(tenantId: number, contactId: number, contactService: TContactService) {
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 contactRepository.deleteById(contactId);
}
/**
* Get contact details of the given contact id.
* @param {number} tenantId
* @param {number} contactId
* @param {TContactService} contactService
* @returns {Promise<IContact>}
*/
async getContact(tenantId: number, contactId: number, contactService: TContactService) {
return this.getContactByIdOrThrowError(tenantId, contactId, contactService);
}
/**
* Retrieve contacts or throw not found error if one of ids were not found
* on the storage.
* @param {number} tenantId
* @param {number[]} contactsIds
* @param {TContactService} contactService
* @return {Promise<IContact>}
*/
async getContactsOrThrowErrorNotFound(tenantId: number, contactsIds: number[], contactService: TContactService) {
const { Contact } = this.tenancy.models(tenantId);
const contacts = await Contact.query().whereIn('id', contactsIds).where('contact_service', contactService);
const storedContactsIds = contacts.map((contact: IContact) => contact.id);
const notFoundCustomers = difference(contactsIds, storedContactsIds);
if (notFoundCustomers.length > 0) {
throw new ServiceError('contacts_not_found');
}
return contacts;
}
/**
* Deletes the given contacts in bulk.
* @param {number} tenantId
* @param {number[]} contactsIds
* @param {TContactService} contactService
* @return {Promise<void>}
*/
async deleteBulkContacts(tenantId: number, contactsIds: number[], contactService: TContactService) {
const { contactRepository } = this.tenancy.repositories(tenantId);
this.getContactsOrThrowErrorNotFound(tenantId, contactsIds, contactService);
await contactRepository.bulkDelete(contactsIds);
}
/**
* Reverts journal entries of the given contacts.
* @param {number} tenantId
* @param {number[]} contactsIds
* @param {TContactService} contactService
*/
async revertJEntriesContactsOpeningBalance(
tenantId: number,
contactsIds: number[],
contactService: TContactService
) {
const { AccountTransaction } = this.tenancy.models(tenantId);
const journal = new JournalPoster(tenantId);
const contactsTransactions = await AccountTransaction.query()
.whereIn('reference_id', contactsIds)
.where('reference_type', `${upperFirst(contactService)}OpeningBalance`);
journal.loadEntries(contactsTransactions);
journal.removeEntries();
await Promise.all([
journal.saveBalance(),
journal.deleteEntries(),
]);
}
}