mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 05:40:31 +00:00
fix: assign contacts customer/vendor in make jorunal.
This commit is contained in:
@@ -51,6 +51,7 @@ export default function ContactsSuggestField({
|
||||
<MenuItem
|
||||
key={contact.id}
|
||||
text={contact.display_name}
|
||||
label={contact.formatted_contact_service}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
),
|
||||
|
||||
@@ -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],
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
}}
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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']),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<void> {
|
||||
const { Account, Contact } = this.tenancy.models(tenantId);
|
||||
): Promise<void | ServiceError> {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user