mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
fix: assign contacts customer/vendor in make jorunal.
This commit is contained in:
@@ -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}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -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'}
|
||||||
|
|||||||
@@ -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']),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -803,7 +828,7 @@ export default class ManualJournalsService implements IManualJournalsService {
|
|||||||
|
|
||||||
return manualJournal;
|
return manualJournal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverts the manual journal journal entries.
|
* Reverts the manual journal journal entries.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
|
|||||||
Reference in New Issue
Block a user