fix: assign contacts customer/vendor in make jorunal.

This commit is contained in:
a.bouhuolia
2021-04-19 18:14:43 +02:00
parent fbe39b8e9d
commit 537150b222
8 changed files with 52 additions and 36 deletions

View File

@@ -51,6 +51,7 @@ export default function ContactsSuggestField({
<MenuItem <MenuItem
key={contact.id} key={contact.id}
text={contact.display_name} text={contact.display_name}
label={contact.formatted_contact_service}
onClick={handleClick} onClick={handleClick}
/> />
), ),

View File

@@ -12,10 +12,7 @@ export default function ContactsListCellRenderer({
}) { }) {
const handleContactSelected = useCallback( const handleContactSelected = useCallback(
(contact) => { (contact) => {
updateData(index, id, { updateData(index, 'contact_id', contact.id);
contact_id: contact.id,
contact_type: contact.contact_type,
});
}, },
[updateData, index, id], [updateData, index, id],
); );

View File

@@ -25,7 +25,7 @@ export default function MakeJournalEntriesTable({
minLinesNumber = 4, minLinesNumber = 4,
currencyCode, currencyCode,
}) { }) {
const { accounts, customers } = useMakeJournalFormContext(); const { accounts, contacts } = useMakeJournalFormContext();
// Memorized data table columns. // Memorized data table columns.
const columns = useJournalTableEntriesColumns(); const columns = useJournalTableEntriesColumns();
@@ -68,10 +68,7 @@ export default function MakeJournalEntriesTable({
errors: error, errors: error,
updateData: handleUpdateData, updateData: handleUpdateData,
removeRow: handleRemoveRow, removeRow: handleRemoveRow,
contacts: customers.map((customer) => ({ contacts,
...customer,
contact_type: 'customer',
})),
autoFocus: ['account_id', 0], autoFocus: ['account_id', 0],
currencyCode, currencyCode,
}} }}

View File

@@ -2,7 +2,7 @@ import React, { createContext, useState } from 'react';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { import {
useAccounts, useAccounts,
useCustomers, useAutoCompleteContacts,
useCurrencies, useCurrencies,
useJournal, useJournal,
useCreateJournal, useCreateJournal,
@@ -21,9 +21,9 @@ function MakeJournalProvider({ journalId, ...props }) {
// Load the customers list. // Load the customers list.
const { const {
data: { customers }, data: contacts,
isLoading: isCustomersLoading, isLoading: isContactsLoading,
} = useCustomers(); } = useAutoCompleteContacts();
// Load the currencies list. // Load the currencies list.
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
@@ -47,7 +47,7 @@ function MakeJournalProvider({ journalId, ...props }) {
const provider = { const provider = {
accounts, accounts,
customers, contacts,
currencies, currencies,
manualJournal, manualJournal,
@@ -55,7 +55,7 @@ function MakeJournalProvider({ journalId, ...props }) {
editJournalMutate, editJournalMutate,
isAccountsLoading, isAccountsLoading,
isCustomersLoading, isContactsLoading,
isCurrenciesLoading, isCurrenciesLoading,
isJournalLoading, isJournalLoading,
isSettingsLoading, isSettingsLoading,
@@ -72,7 +72,7 @@ function MakeJournalProvider({ journalId, ...props }) {
isJournalLoading || isJournalLoading ||
isAccountsLoading || isAccountsLoading ||
isCurrenciesLoading || isCurrenciesLoading ||
isCustomersLoading || isContactsLoading ||
isSettingsLoading isSettingsLoading
} }
name={'make-journal-page'} name={'make-journal-page'}

View File

@@ -128,7 +128,6 @@ export default class ManualJournalsController extends BaseController {
.optional({ nullable: true }) .optional({ nullable: true })
.isInt({ max: DATATYPES_LENGTH.INT_10 }) .isInt({ max: DATATYPES_LENGTH.INT_10 })
.toInt(), .toInt(),
check('entries.*.contact_type').optional().isIn(['vendor', 'customer']),
]; ];
} }

View File

@@ -6,7 +6,6 @@ exports.up = function(knex) {
table.decimal('debit', 13, 3); table.decimal('debit', 13, 3);
table.integer('index').unsigned(); table.integer('index').unsigned();
table.integer('account_id').unsigned().index().references('id').inTable('accounts'); table.integer('account_id').unsigned().index().references('id').inTable('accounts');
table.string('contact_type').nullable().index();
table.integer('contact_id').unsigned().nullable().index(); table.integer('contact_id').unsigned().nullable().index();
table.string('note'); table.string('note');
table.integer('manual_journal_id').unsigned().index().references('id').inTable('manual_journals'); table.integer('manual_journal_id').unsigned().index().references('id').inTable('manual_journals');

View File

@@ -25,7 +25,6 @@ export interface IManualJournalEntry {
accountId: number; accountId: number;
note: string; note: string;
contactId?: number; contactId?: number;
contactType?: string;
} }
export interface IManualJournalEntryDTO { export interface IManualJournalEntryDTO {
@@ -35,7 +34,6 @@ export interface IManualJournalEntryDTO {
accountId: number; accountId: number;
note: string; note: string;
contactId?: number; contactId?: number;
contactType?: string;
} }
export interface IManualJournalDTO { export interface IManualJournalDTO {

View File

@@ -1,7 +1,7 @@
import { difference, sumBy, omit, map } from 'lodash'; import { difference, sumBy, omit, map } from 'lodash';
import { Service, Inject } from 'typedi'; import { Service, Inject } from 'typedi';
import moment from 'moment'; import moment from 'moment';
import { ServiceError } from 'exceptions'; import { ServiceError, ServiceErrors } from 'exceptions';
import { import {
IManualJournalDTO, IManualJournalDTO,
IManualJournalsService, IManualJournalsService,
@@ -187,15 +187,27 @@ export default class ManualJournalsService implements IManualJournalsService {
private async validateAccountWithContactType( private async validateAccountWithContactType(
tenantId: number, tenantId: number,
entriesDTO: IManualJournalEntry[], entriesDTO: IManualJournalEntry[],
accountBySlug: string, accountBySlug: string,
contactType: string contactType: string
): Promise<void> { ): Promise<void | ServiceError> {
const { Account, Contact } = this.tenancy.models(tenantId); const { Account } = this.tenancy.models(tenantId);
const { contactRepository } = this.tenancy.repositories(tenantId);
// Retrieve account meta by the given account slug. // Retrieve account meta by the given account slug.
const account = await Account.query().findOne('slug', accountBySlug); 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. // Filter all entries of the given account.
const accountEntries = entriesDTO.filter( const accountEntries = entriesDTO.filter(
(entry) => entry.accountId === account.id (entry) => entry.accountId === account.id
@@ -205,14 +217,15 @@ export default class ManualJournalsService implements IManualJournalsService {
return; return;
} }
// Filter entries that have no contact type or not equal the valid type. // Filter entries that have no contact type or not equal the valid type.
const entriesNoContact = accountEntries.filter( const entriesNoContact = accountEntries.filter((entry) => {
(entry) => !entry.contactType || entry.contactType !== contactType const contact = storedContactsMap.get(entry.contactId);
); return !contact || contact.contactService !== contactType;
});
// Throw error in case one of entries that has invalid contact type. // Throw error in case one of entries that has invalid contact type.
if (entriesNoContact.length > 0) { if (entriesNoContact.length > 0) {
const indexes = entriesNoContact.map((e) => e.index); 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, accountSlug: accountBySlug,
contactType, contactType,
indexes, indexes,
@@ -242,11 +255,25 @@ export default class ManualJournalsService implements IManualJournalsService {
'accounts-payable', 'accounts-payable',
'vendor' '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 {number} tenantId -
* @param {IManualJournalDTO} manualJournalDTO * @param {IManualJournalDTO} manualJournalDTO
*/ */
@@ -280,10 +307,7 @@ export default class ManualJournalsService implements IManualJournalsService {
const storedContact = storedContactsMap.get(contactEntry.contactId); const storedContact = storedContactsMap.get(contactEntry.contactId);
// in case the contact id not found. // in case the contact id not found.
if ( if (!storedContact) {
!storedContact ||
storedContact.contactService !== contactEntry.contactType
) {
notFoundContactsIds.push(storedContact); notFoundContactsIds.push(storedContact);
} }
}); });
@@ -347,7 +371,8 @@ export default class ManualJournalsService implements IManualJournalsService {
// Settings tenant service. // Settings tenant service.
const settings = this.tenancy.settings(tenantId); const settings = this.tenancy.settings(tenantId);
const currencyCode = settings.get({ const currencyCode = settings.get({
group: 'organization', key: 'base_currency', group: 'organization',
key: 'base_currency',
}); });
// Validate manual journal number require. // Validate manual journal number require.
this.validateJournalNoRequire(journalNumber); this.validateJournalNoRequire(journalNumber);