Merge branch 'develop' into contacts-opening-balance-exchange-rate

This commit is contained in:
Ahmed Bouhuolia
2023-06-11 19:56:54 +02:00
8 changed files with 60 additions and 12 deletions

View File

@@ -4,6 +4,8 @@ export interface ILedger {
getEntries(): ILedgerEntry[];
filter(cb: (entry: ILedgerEntry) => boolean): ILedger;
whereAccountId(accountId: number): ILedger;
whereContactId(contactId: number): ILedger;
whereFromDate(fromDate: Date | string): ILedger;

View File

@@ -1,9 +1,14 @@
import { Service, Inject } from 'typedi';
import async from 'async';
import { Knex } from 'knex';
import { ILedger, ISaleContactsBalanceQueuePayload } from '@/interfaces';
import {
ILedger,
ILedgerEntry,
ISaleContactsBalanceQueuePayload,
} from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { TenantMetadata } from '@/system/models';
import { ACCOUNT_TYPE } from '@/data/AccountTypes';
@Service()
export class LedgerContactsBalanceStorage {
@@ -49,6 +54,29 @@ export class LedgerContactsBalanceStorage {
await this.saveContactBalance(tenantId, ledger, contactId, trx);
};
/**
* Filters AP/AR ledger entries.
* @param {number} tenantId
* @param {Knex.Transaction} trx
* @returns {Promise<(entry: ILedgerEntry) => boolean>}
*/
private filterARAPLedgerEntris = async (
tenantId: number,
trx?: Knex.Transaction
): Promise<(entry: ILedgerEntry) => boolean> => {
const { Account } = this.tenancy.models(tenantId);
const ARAPAcounts = await Account.query(trx).whereIn('accountType', [
ACCOUNT_TYPE.ACCOUNTS_RECEIVABLE,
ACCOUNT_TYPE.ACCOUNTS_PAYABLE,
]);
const ARAPAcountsIds = ARAPAcounts.map((a) => a.id);
return (entry: ILedgerEntry) => {
return ARAPAcountsIds.indexOf(entry.accountId) !== -1;
};
};
/**
*
* @param {number} tenantId
@@ -63,16 +91,24 @@ export class LedgerContactsBalanceStorage {
trx?: Knex.Transaction
): Promise<void> => {
const { Contact } = this.tenancy.models(tenantId);
const contact = await Contact.query().findById(contactId);
const contact = await Contact.query(trx).findById(contactId);
// Retrieves the given tenant metadata.
const tenantMeta = await TenantMetadata.query().findOne({ tenantId });
// Detarmines whether the contact has foreign currency.
const isForeignContact = contact.currencyCode !== tenantMeta.baseCurrency;
// Filters the ledger base on the given contact id.
const contactLedger = ledger.whereContactId(contactId);
const filterARAPLedgerEntris = await this.filterARAPLedgerEntris(
tenantId,
trx
);
const contactLedger = ledger
// Filter entries only that have contact id.
.whereContactId(contactId)
// Filter entries on AR/AP accounts.
.filter(filterARAPLedgerEntris);
const closingBalance = isForeignContact
? contactLedger

View File

@@ -55,7 +55,7 @@ export class CreateCustomer {
} as ICustomerEventCreatingPayload);
// Creates a new contact as customer.
const customer = await Contact.query().insertAndFetch({
const customer = await Contact.query(trx).insertAndFetch({
...customerObj,
});
// Triggers `onCustomerCreated` event.

View File

@@ -28,6 +28,8 @@ const ERROR = {
CREDIT_DEBIT_SUMATION_SHOULD_NOT_EQUAL_ZERO:
'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO',
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
COULD_NOT_ASSIGN_DIFFERENT_CURRENCY_TO_ACCOUNTS:
'COULD_NOT_ASSIGN_DIFFERENT_CURRENCY_TO_ACCOUNTS',
};
export const MIN_LINES_NUMBER = 1;
@@ -161,6 +163,15 @@ export const transformErrors = (resErrors, { setErrors, errors }) => {
intl.get('journal_number_is_already_used'),
);
}
if (
(error = getError(ERROR.COULD_NOT_ASSIGN_DIFFERENT_CURRENCY_TO_ACCOUNTS))
) {
toastMessages.push(
intl.get(
'make_journal.errors.should_add_accounts_in_same_currency_or_base_currency',
),
);
}
setErrors({ ...newErrors });
if (toastMessages.length > 0) {

View File

@@ -38,7 +38,6 @@ export function ActionsMenu({
/>
<Can I={CustomerAction.Edit} a={AbilitySubject.Customer}>
<MenuDivider />
<MenuItem
icon={<Icon icon="pen-18" />}
text={intl.get('edit_customer')}
@@ -47,7 +46,7 @@ export function ActionsMenu({
</Can>
<Can I={CustomerAction.Create} a={AbilitySubject.Customer}>
<MenuItem
icon={<Icon icon="duplicate-16" />}
icon={<Icon icon="content-copy" iconSize={16} />}
text={intl.get('duplicate')}
onClick={safeCallback(onDuplicate, original)}
/>

View File

@@ -8,7 +8,6 @@ import { useCustomerOpeningBalanceContext } from './CustomerOpeningBalanceFormPr
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { compose } from '@/utils';
/**
* Customer Opening balance floating actions.
* @returns
@@ -31,6 +30,9 @@ function CustomerOpeningBalanceFormFloatingActions({
return (
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button onClick={handleCancelBtnClick} style={{ minWidth: '75px' }}>
<T id={'cancel'} />
</Button>
<Button
intent={Intent.PRIMARY}
loading={isSubmitting}
@@ -39,9 +41,6 @@ function CustomerOpeningBalanceFormFloatingActions({
>
{<T id={'edit'} />}
</Button>
<Button onClick={handleCancelBtnClick} style={{ minWidth: '75px' }}>
<T id={'cancel'} />
</Button>
</div>
</div>
);

View File

@@ -48,7 +48,7 @@ export function ActionsMenu({
</Can>
<Can I={VendorAction.Create} a={AbilitySubject.Customer}>
<MenuItem
icon={<Icon icon="duplicate-16" />}
icon={<Icon icon="content-copy" iconSize={16} />}
text={intl.get('duplicate')}
onClick={safeCallback(onDuplicate, original)}
/>

View File

@@ -703,6 +703,7 @@
"email_is_already_used": "The email is already used.",
"the_item_categories_has_been_deleted_successfully": "The item categories has been deleted successfully .",
"receivable_accounts_should_assign_with_customers": "Receivable accounts should assign with customers.",
"make_journal.errors.should_add_accounts_in_same_currency_or_base_currency": "You can only add accounts that have the same selected currency or base currency.",
"delivered": "Delivered",
"save_and_deliver": "Save & Deliver",
"deliver_and_new": "Deliver and new",