diff --git a/client/src/components/ContactsSuggestField.js b/client/src/components/ContactsSuggestField.js index 6e165d2c8..3e5b8ecad 100644 --- a/client/src/components/ContactsSuggestField.js +++ b/client/src/components/ContactsSuggestField.js @@ -51,6 +51,7 @@ export default function ContactsSuggestField({ ), diff --git a/client/src/components/DataTableCells/ContactsListFieldCell.js b/client/src/components/DataTableCells/ContactsListFieldCell.js index ee1b72fc9..468764d62 100644 --- a/client/src/components/DataTableCells/ContactsListFieldCell.js +++ b/client/src/components/DataTableCells/ContactsListFieldCell.js @@ -12,10 +12,7 @@ export default function ContactsListCellRenderer({ }) { const handleContactSelected = useCallback( (contact) => { - updateData(index, id, { - contact_id: contact.id, - contact_type: contact.contact_type, - }); + updateData(index, 'contact_id', contact.id); }, [updateData, index, id], ); diff --git a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js index ac61fadde..5828aa31f 100644 --- a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js +++ b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js @@ -25,7 +25,7 @@ export default function MakeJournalEntriesTable({ minLinesNumber = 4, currencyCode, }) { - const { accounts, customers } = useMakeJournalFormContext(); + const { accounts, contacts } = useMakeJournalFormContext(); // Memorized data table columns. const columns = useJournalTableEntriesColumns(); @@ -68,10 +68,7 @@ export default function MakeJournalEntriesTable({ errors: error, updateData: handleUpdateData, removeRow: handleRemoveRow, - contacts: customers.map((customer) => ({ - ...customer, - contact_type: 'customer', - })), + contacts, autoFocus: ['account_id', 0], currencyCode, }} diff --git a/client/src/containers/Accounting/MakeJournal/MakeJournalProvider.js b/client/src/containers/Accounting/MakeJournal/MakeJournalProvider.js index beab5394b..2241ff28c 100644 --- a/client/src/containers/Accounting/MakeJournal/MakeJournalProvider.js +++ b/client/src/containers/Accounting/MakeJournal/MakeJournalProvider.js @@ -2,7 +2,7 @@ import React, { createContext, useState } from 'react'; import DashboardInsider from 'components/Dashboard/DashboardInsider'; import { useAccounts, - useCustomers, + useAutoCompleteContacts, useCurrencies, useJournal, useCreateJournal, @@ -21,9 +21,9 @@ function MakeJournalProvider({ journalId, ...props }) { // Load the customers list. const { - data: { customers }, - isLoading: isCustomersLoading, - } = useCustomers(); + data: contacts, + isLoading: isContactsLoading, + } = useAutoCompleteContacts(); // Load the currencies list. const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); @@ -47,7 +47,7 @@ function MakeJournalProvider({ journalId, ...props }) { const provider = { accounts, - customers, + contacts, currencies, manualJournal, @@ -55,7 +55,7 @@ function MakeJournalProvider({ journalId, ...props }) { editJournalMutate, isAccountsLoading, - isCustomersLoading, + isContactsLoading, isCurrenciesLoading, isJournalLoading, isSettingsLoading, @@ -72,7 +72,7 @@ function MakeJournalProvider({ journalId, ...props }) { isJournalLoading || isAccountsLoading || isCurrenciesLoading || - isCustomersLoading || + isContactsLoading || isSettingsLoading } name={'make-journal-page'} diff --git a/server/src/api/controllers/ManualJournals.ts b/server/src/api/controllers/ManualJournals.ts index eec84227a..288adc3e8 100644 --- a/server/src/api/controllers/ManualJournals.ts +++ b/server/src/api/controllers/ManualJournals.ts @@ -128,7 +128,6 @@ export default class ManualJournalsController extends BaseController { .optional({ nullable: true }) .isInt({ max: DATATYPES_LENGTH.INT_10 }) .toInt(), - check('entries.*.contact_type').optional().isIn(['vendor', 'customer']), ]; } diff --git a/server/src/database/migrations/20200105195825_create_manual_journals_entries_table.js b/server/src/database/migrations/20200105195825_create_manual_journals_entries_table.js index b061f9fb5..ecf22cf4c 100644 --- a/server/src/database/migrations/20200105195825_create_manual_journals_entries_table.js +++ b/server/src/database/migrations/20200105195825_create_manual_journals_entries_table.js @@ -6,7 +6,6 @@ exports.up = function(knex) { table.decimal('debit', 13, 3); table.integer('index').unsigned(); table.integer('account_id').unsigned().index().references('id').inTable('accounts'); - table.string('contact_type').nullable().index(); table.integer('contact_id').unsigned().nullable().index(); table.string('note'); table.integer('manual_journal_id').unsigned().index().references('id').inTable('manual_journals'); diff --git a/server/src/interfaces/ManualJournal.ts b/server/src/interfaces/ManualJournal.ts index 2e18d61b5..0b0061c96 100644 --- a/server/src/interfaces/ManualJournal.ts +++ b/server/src/interfaces/ManualJournal.ts @@ -25,7 +25,6 @@ export interface IManualJournalEntry { accountId: number; note: string; contactId?: number; - contactType?: string; } export interface IManualJournalEntryDTO { @@ -35,7 +34,6 @@ export interface IManualJournalEntryDTO { accountId: number; note: string; contactId?: number; - contactType?: string; } export interface IManualJournalDTO { diff --git a/server/src/services/ManualJournals/ManualJournalsService.ts b/server/src/services/ManualJournals/ManualJournalsService.ts index 180b27059..bedd8ab63 100644 --- a/server/src/services/ManualJournals/ManualJournalsService.ts +++ b/server/src/services/ManualJournals/ManualJournalsService.ts @@ -1,7 +1,7 @@ import { difference, sumBy, omit, map } from 'lodash'; import { Service, Inject } from 'typedi'; import moment from 'moment'; -import { ServiceError } from 'exceptions'; +import { ServiceError, ServiceErrors } from 'exceptions'; import { IManualJournalDTO, IManualJournalsService, @@ -187,15 +187,27 @@ export default class ManualJournalsService implements IManualJournalsService { private async validateAccountWithContactType( tenantId: number, entriesDTO: IManualJournalEntry[], - accountBySlug: string, contactType: string - ): Promise { - const { Account, Contact } = this.tenancy.models(tenantId); + ): Promise { + const { Account } = this.tenancy.models(tenantId); + const { contactRepository } = this.tenancy.repositories(tenantId); // Retrieve account meta by the given account slug. const account = await Account.query().findOne('slug', accountBySlug); + // Retrieve all stored contacts on the storage from contacts entries. + const storedContacts = await contactRepository.findWhereIn( + 'id', + entriesDTO + .filter((entry) => entry.contactId) + .map((entry) => entry.contactId) + ); + // Converts the stored contacts to map with id as key and entry as value. + const storedContactsMap = new Map( + storedContacts.map((contact) => [contact.id, contact]) + ); + // Filter all entries of the given account. const accountEntries = entriesDTO.filter( (entry) => entry.accountId === account.id @@ -205,14 +217,15 @@ export default class ManualJournalsService implements IManualJournalsService { return; } // Filter entries that have no contact type or not equal the valid type. - const entriesNoContact = accountEntries.filter( - (entry) => !entry.contactType || entry.contactType !== contactType - ); + const entriesNoContact = accountEntries.filter((entry) => { + const contact = storedContactsMap.get(entry.contactId); + return !contact || contact.contactService !== contactType; + }); // Throw error in case one of entries that has invalid contact type. if (entriesNoContact.length > 0) { const indexes = entriesNoContact.map((e) => e.index); - throw new ServiceError(ERRORS.ENTRIES_SHOULD_ASSIGN_WITH_CONTACT, '', { + return new ServiceError(ERRORS.ENTRIES_SHOULD_ASSIGN_WITH_CONTACT, '', { accountSlug: accountBySlug, contactType, indexes, @@ -242,11 +255,25 @@ export default class ManualJournalsService implements IManualJournalsService { 'accounts-payable', 'vendor' ), - ]); + ]).then((results) => { + const metadataErrors = results + .filter((result) => result instanceof ServiceError) + .map((result: ServiceError) => result.payload); + + if (metadataErrors.length > 0) { + throw new ServiceError( + ERRORS.ENTRIES_SHOULD_ASSIGN_WITH_CONTACT, + '', + metadataErrors + ); + } + + return results; + }); } /** - * Vaplidate entries contacts existance. + * Validate entries contacts existance. * @param {number} tenantId - * @param {IManualJournalDTO} manualJournalDTO */ @@ -280,10 +307,7 @@ export default class ManualJournalsService implements IManualJournalsService { const storedContact = storedContactsMap.get(contactEntry.contactId); // in case the contact id not found. - if ( - !storedContact || - storedContact.contactService !== contactEntry.contactType - ) { + if (!storedContact) { notFoundContactsIds.push(storedContact); } }); @@ -347,7 +371,8 @@ export default class ManualJournalsService implements IManualJournalsService { // Settings tenant service. const settings = this.tenancy.settings(tenantId); const currencyCode = settings.get({ - group: 'organization', key: 'base_currency', + group: 'organization', + key: 'base_currency', }); // Validate manual journal number require. this.validateJournalNoRequire(journalNumber); @@ -803,7 +828,7 @@ export default class ManualJournalsService implements IManualJournalsService { return manualJournal; } - + /** * Reverts the manual journal journal entries. * @param {number} tenantId