mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
fix: FastField re-rendering.
fix: Allocate landed cost dialog.
This commit is contained in:
@@ -67,4 +67,4 @@ export const useManualJournalsColumns = () => {
|
||||
],
|
||||
[],
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -3,16 +3,28 @@ import { FastField } from 'formik';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import MakeJournalEntriesTable from './MakeJournalEntriesTable';
|
||||
import { defaultEntry, MIN_LINES_NUMBER } from './utils';
|
||||
import { entriesFieldShouldUpdate, defaultEntry, MIN_LINES_NUMBER } from './utils';
|
||||
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||
|
||||
/**
|
||||
* Make journal entries field.
|
||||
*/
|
||||
export default function MakeJournalEntriesField() {
|
||||
const { accounts, contacts } = useMakeJournalFormContext();
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||
<FastField name={'entries'}>
|
||||
{({ form:{values ,setFieldValue}, field: { value }, meta: { error, touched } }) => (
|
||||
<FastField
|
||||
name={'entries'}
|
||||
contacts={contacts}
|
||||
accounts={accounts}
|
||||
shouldUpdate={entriesFieldShouldUpdate}
|
||||
>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<MakeJournalEntriesTable
|
||||
onChange={(entries) => {
|
||||
setFieldValue('entries', entries);
|
||||
|
||||
@@ -29,7 +29,10 @@ import {
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import { useObserveJournalNoSettings } from './utils';
|
||||
import {
|
||||
currenciesFieldShouldUpdate,
|
||||
useObserveJournalNoSettings,
|
||||
} from './utils';
|
||||
/**
|
||||
* Make journal entries header.
|
||||
*/
|
||||
@@ -182,7 +185,11 @@ function MakeJournalEntriesHeader({
|
||||
</FastField>
|
||||
|
||||
{/*------------ Currency -----------*/}
|
||||
<FastField name={'currency_code'}>
|
||||
<FastField
|
||||
name={'currency_code'}
|
||||
currencies={currencies}
|
||||
shouldUpdate={currenciesFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'currency'} />}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { sumBy, setWith, toSafeInteger, get, values } from 'lodash';
|
||||
import { sumBy, setWith, toSafeInteger, get } from 'lodash';
|
||||
import moment from 'moment';
|
||||
|
||||
import {
|
||||
transactionNumber,
|
||||
updateTableRow,
|
||||
repeatValue,
|
||||
transformToForm,
|
||||
defaultFastFieldShouldUpdate,
|
||||
} from 'utils';
|
||||
import { AppToaster } from 'components';
|
||||
import intl from 'react-intl-universal';
|
||||
@@ -123,17 +123,17 @@ export const transformErrors = (resErrors, { setErrors, errors }) => {
|
||||
setEntriesErrors(error.indexes, 'contact_id', 'error');
|
||||
}
|
||||
if ((error = getError(ERROR.ENTRIES_SHOULD_ASSIGN_WITH_CONTACT))) {
|
||||
if (error.meta.find(meta => meta.contact_type === 'customer')) {
|
||||
if (error.meta.find((meta) => meta.contact_type === 'customer')) {
|
||||
toastMessages.push(
|
||||
intl.get('receivable_accounts_should_assign_with_customers'),
|
||||
);
|
||||
}
|
||||
if (error.meta.find(meta => meta.contact_type === 'vendor')) {
|
||||
if (error.meta.find((meta) => meta.contact_type === 'vendor')) {
|
||||
toastMessages.push(
|
||||
intl.get('payable_accounts_should_assign_with_vendors'),
|
||||
);
|
||||
}
|
||||
const indexes = error.meta.map((meta => meta.indexes)).flat();
|
||||
const indexes = error.meta.map((meta) => meta.indexes).flat();
|
||||
setEntriesErrors(indexes, 'contact_id', 'error');
|
||||
}
|
||||
if ((error = getError(ERROR.JOURNAL_NUMBER_ALREADY_EXISTS))) {
|
||||
@@ -159,7 +159,28 @@ export const useObserveJournalNoSettings = (prefix, nextNumber) => {
|
||||
const { setFieldValue } = useFormikContext();
|
||||
|
||||
React.useEffect(() => {
|
||||
const journalNo = transactionNumber(prefix, nextNumber);
|
||||
const journalNo = transactionNumber(prefix, nextNumber);
|
||||
setFieldValue('journal_number', journalNo);
|
||||
}, [setFieldValue, prefix, nextNumber]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines entries fast field should update.
|
||||
*/
|
||||
export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
newProps.contacts !== oldProps.contacts ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines currencies fast field should update.
|
||||
*/
|
||||
export const currenciesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.currencies !== oldProps.currencies ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ function BillTransactionDeleteAlert({
|
||||
onConfirm={handleConfirmLandedCostDelete}
|
||||
loading={isLoading}
|
||||
>
|
||||
<p>{/* <T id={''}/> */}</p>
|
||||
<p><T id={`Once your delete this located landed cost, you won't be able to restore it later, Are your sure you want to delete this transaction?`}/></p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { Formik } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
import moment from 'moment';
|
||||
import { sumBy } from 'lodash';
|
||||
|
||||
import 'style/pages/AllocateLandedCost/AllocateLandedCostForm.scss';
|
||||
|
||||
@@ -48,6 +49,7 @@ function AllocateLandedCostForm({
|
||||
cost: '',
|
||||
})),
|
||||
};
|
||||
const amount = sumBy(initialValues.items, 'amount');
|
||||
|
||||
// Handle form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting }) => {
|
||||
@@ -84,9 +86,12 @@ function AllocateLandedCostForm({
|
||||
createLandedCostMutate([billId, form]).then(onSuccess).catch(onError);
|
||||
};
|
||||
|
||||
// Computed validation schema.
|
||||
const validationSchema = AllocateLandedCostFormSchema(amount);
|
||||
|
||||
return (
|
||||
<Formik
|
||||
validationSchema={AllocateLandedCostFormSchema}
|
||||
validationSchema={validationSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
component={AllocateLandedCostFormContent}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import * as Yup from 'yup';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
const Schema = Yup.object().shape({
|
||||
transaction_type: Yup.string().label(intl.get('transaction_type')),
|
||||
transaction_date: Yup.date().label(intl.get('transaction_date')),
|
||||
transaction_id: Yup.string().label(intl.get('transaction_number')),
|
||||
transaction_entry_id: Yup.string().label(intl.get('transaction_line')),
|
||||
amount: Yup.number().label(intl.get('amount')),
|
||||
allocation_method: Yup.string().trim(),
|
||||
items: Yup.array().of(
|
||||
Yup.object().shape({
|
||||
entry_id: Yup.number().nullable(),
|
||||
cost: Yup.number().nullable(),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
export const AllocateLandedCostFormSchema = Schema;
|
||||
export const AllocateLandedCostFormSchema = (minAmount) =>
|
||||
Yup.object().shape({
|
||||
transaction_type: Yup.string().label(intl.get('transaction_type')),
|
||||
transaction_date: Yup.date().label(intl.get('transaction_date')),
|
||||
transaction_id: Yup.string().label(intl.get('transaction_number')),
|
||||
transaction_entry_id: Yup.string().label(intl.get('transaction_line')),
|
||||
amount: Yup.number().max(minAmount).label(intl.get('amount')),
|
||||
allocation_method: Yup.string().trim(),
|
||||
items: Yup.array().of(
|
||||
Yup.object().shape({
|
||||
entry_id: Yup.number().nullable(),
|
||||
cost: Yup.number().nullable(),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ import allocateLandedCostType from 'common/allocateLandedCostType';
|
||||
import { useLandedCostTransaction } from 'hooks/query';
|
||||
|
||||
import AllocateLandedCostFormBody from './AllocateLandedCostFormBody';
|
||||
import { getEntriesByTransactionId } from './utils';
|
||||
import { getEntriesByTransactionId, allocateCostToEntries } from './utils';
|
||||
|
||||
/**
|
||||
* Allocate landed cost form fields.
|
||||
@@ -30,10 +30,10 @@ export default function AllocateLandedCostFormFields() {
|
||||
} = useLandedCostTransaction(values.transaction_type);
|
||||
|
||||
// Retrieve entries of the given transaction id.
|
||||
const transactionEntries = React.useMemo(() => getEntriesByTransactionId(
|
||||
transactions,
|
||||
values.transaction_id,
|
||||
), [transactions, values.transaction_id]);
|
||||
const transactionEntries = React.useMemo(
|
||||
() => getEntriesByTransactionId(transactions, values.transaction_id),
|
||||
[transactions, values.transaction_id],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
@@ -56,6 +56,8 @@ export default function AllocateLandedCostFormFields() {
|
||||
items={allocateLandedCostType}
|
||||
onItemSelect={(type) => {
|
||||
setFieldValue('transaction_type', type.value);
|
||||
setFieldValue('transaction_id', '');
|
||||
setFieldValue('transaction_entry_id', '');
|
||||
}}
|
||||
filterable={false}
|
||||
selectedItem={value}
|
||||
@@ -82,13 +84,14 @@ export default function AllocateLandedCostFormFields() {
|
||||
items={transactions}
|
||||
onItemSelect={({ id }) => {
|
||||
form.setFieldValue('transaction_id', id);
|
||||
form.setFieldValue('transaction_entry_id', '');
|
||||
}}
|
||||
filterable={false}
|
||||
selectedItem={value}
|
||||
selectedItemProp={'id'}
|
||||
textProp={'name'}
|
||||
labelProp={'id'}
|
||||
defaultText={intl.get('select_transaction')}
|
||||
defaultText={intl.get('Select transaction')}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FormGroup>
|
||||
@@ -112,15 +115,21 @@ export default function AllocateLandedCostFormFields() {
|
||||
<ListSelect
|
||||
items={transactionEntries}
|
||||
onItemSelect={({ id, amount }) => {
|
||||
form.setFieldValue('amount', amount)
|
||||
const { items, allocation_method } = form.values;
|
||||
|
||||
form.setFieldValue('amount', amount);
|
||||
form.setFieldValue('transaction_entry_id', id);
|
||||
|
||||
form.setFieldValue(
|
||||
'items',
|
||||
allocateCostToEntries(amount, allocation_method, items),
|
||||
);
|
||||
}}
|
||||
filterable={false}
|
||||
selectedItem={value}
|
||||
selectedItemProp={'id'}
|
||||
textProp={'name'}
|
||||
labelProp={'id'}
|
||||
defaultText={intl.get('select_transaction')}
|
||||
defaultText={intl.get('Select transaction entry')}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FormGroup>
|
||||
@@ -138,13 +147,24 @@ export default function AllocateLandedCostFormFields() {
|
||||
className={'form-group--amount'}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup {...field} />
|
||||
<InputGroup
|
||||
{...field}
|
||||
onBlur={(e) => {
|
||||
const amount = e.target.value;
|
||||
const { allocation_method, items } = form.values;
|
||||
|
||||
form.setFieldValue(
|
||||
'items',
|
||||
allocateCostToEntries(amount, allocation_method, items),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/*------------ Allocation method -----------*/}
|
||||
<FastField name={'allocation_method'}>
|
||||
<Field name={'allocation_method'}>
|
||||
{({ form, field: { value }, meta: { touched, error } }) => (
|
||||
<FormGroup
|
||||
medium={true}
|
||||
@@ -157,7 +177,13 @@ export default function AllocateLandedCostFormFields() {
|
||||
>
|
||||
<RadioGroup
|
||||
onChange={handleStringChange((_value) => {
|
||||
const { amount, items, allocation_method } = form.values;
|
||||
|
||||
form.setFieldValue('allocation_method', _value);
|
||||
form.setFieldValue(
|
||||
'items',
|
||||
allocateCostToEntries(amount, allocation_method, items),
|
||||
);
|
||||
})}
|
||||
selectedValue={value}
|
||||
inline={true}
|
||||
@@ -167,7 +193,7 @@ export default function AllocateLandedCostFormFields() {
|
||||
</RadioGroup>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</Field>
|
||||
|
||||
{/*------------ Allocate Landed cost Table -----------*/}
|
||||
<AllocateLandedCostFormBody />
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { sumBy, round } from 'lodash';
|
||||
import * as R from 'ramda';
|
||||
/**
|
||||
* Retrieve transaction entries of the given transaction id.
|
||||
*/
|
||||
@@ -5,3 +7,56 @@ export function getEntriesByTransactionId(transactions, id) {
|
||||
const transaction = transactions.find((trans) => trans.id === id);
|
||||
return transaction ? transaction.entries : [];
|
||||
}
|
||||
|
||||
export function allocateCostToEntries(total, allocateType, entries) {
|
||||
return R.compose(
|
||||
R.when(
|
||||
R.always(allocateType === 'value'),
|
||||
R.curry(allocateCostByValue)(total),
|
||||
),
|
||||
R.when(
|
||||
R.always(allocateType === 'quantity'),
|
||||
R.curry(allocateCostByQuantity)(total),
|
||||
),
|
||||
)(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate total cost on entries on value.
|
||||
* @param {*} entries
|
||||
* @param {*} total
|
||||
* @returns
|
||||
*/
|
||||
export function allocateCostByValue(total, entries) {
|
||||
const totalAmount = sumBy(entries, 'amount');
|
||||
|
||||
const _entries = entries.map((entry) => ({
|
||||
...entry,
|
||||
percentageOfValue: entry.amount / totalAmount,
|
||||
}));
|
||||
|
||||
return _entries.map((entry) => ({
|
||||
...entry,
|
||||
cost: round(entry.percentageOfValue * total, 2),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate total cost on entries by quantity.
|
||||
* @param {*} entries
|
||||
* @param {*} total
|
||||
* @returns
|
||||
*/
|
||||
export function allocateCostByQuantity(total, entries) {
|
||||
const totalQuantity = sumBy(entries, 'quantity');
|
||||
|
||||
const _entries = entries.map((entry) => ({
|
||||
...entry,
|
||||
percentageOfQuantity: entry.quantity / totalQuantity,
|
||||
}));
|
||||
|
||||
return _entries.map((entry) => ({
|
||||
...entry,
|
||||
cost: round(entry.percentageOfQuantity * total, 2),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'style/components/Drawers/AccountDrawer.scss';
|
||||
|
||||
import { AccountDrawerProvider } from './AccountDrawerProvider';
|
||||
import AccountDrawerDetails from './AccountDrawerDetails';
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ import AccountDrawerHeader from './AccountDrawerHeader';
|
||||
import AccountDrawerTable from './AccountDrawerTable';
|
||||
import { useAccountDrawerContext } from './AccountDrawerProvider';
|
||||
|
||||
import 'style/components/Drawer/AccountDrawer.scss';
|
||||
|
||||
/**
|
||||
* Account view details.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import BillTransactionDeleteAlert from 'containers/Alerts/Bills/BillTransactionDeleteAlert';
|
||||
import BillLocatedLandedCostDeleteAlert from 'containers/Alerts/Bills/BillLocatedLandedCostDeleteAlert';
|
||||
|
||||
/**
|
||||
* Bill drawer alert.
|
||||
@@ -7,7 +7,7 @@ import BillTransactionDeleteAlert from 'containers/Alerts/Bills/BillTransactionD
|
||||
export default function BillDrawerAlerts() {
|
||||
return (
|
||||
<div class="bills-alerts">
|
||||
<BillTransactionDeleteAlert name="transaction-delete" />
|
||||
<BillLocatedLandedCostDeleteAlert name="bill-located-cost-delete" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'style/components/Drawers/BillDrawer.scss';
|
||||
|
||||
import { BillDrawerProvider } from './BillDrawerProvider';
|
||||
import BillDrawerDetails from './BillDrawerDetails';
|
||||
import BillDrawerAlerts from './BillDrawerAlerts';
|
||||
|
||||
@@ -4,8 +4,6 @@ import intl from 'react-intl-universal';
|
||||
|
||||
import LocatedLandedCostTable from './LocatedLandedCostTable';
|
||||
|
||||
import 'style/components/Drawer/BillDrawer.scss';
|
||||
|
||||
/**
|
||||
* Bill view details.
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,9 @@ function BillDrawerProvider({ billId, ...props }) {
|
||||
//provider.
|
||||
const provider = {
|
||||
transactions,
|
||||
billId,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider loading={isLandedCostLoading}>
|
||||
<DrawerHeaderContent
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import React from 'react';
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, Card } from 'components';
|
||||
import { Button, Classes, NavbarGroup } from '@blueprintjs/core';
|
||||
|
||||
import { useLocatedLandedCostColumns, ActionsMenu } from './components';
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
import Icon from 'components/Icon';
|
||||
|
||||
/**
|
||||
* Located landed cost table.
|
||||
@@ -13,25 +19,73 @@ import { compose } from 'utils';
|
||||
function LocatedLandedCostTable({
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
const columns = useLocatedLandedCostColumns();
|
||||
const { transactions } = useBillDrawerContext();
|
||||
const { transactions, billId } = useBillDrawerContext();
|
||||
|
||||
// Handle the transaction delete action.
|
||||
const handleDeleteTransaction = ({ id }) => {
|
||||
openAlert('transaction-delete', { BillId: id });
|
||||
openAlert('bill-located-cost-delete', { BillId: id });
|
||||
};
|
||||
|
||||
// Handle allocate landed cost button click.
|
||||
const handleAllocateCostClick = () => {
|
||||
openDialog('allocate-landed-cost', { billId });
|
||||
};
|
||||
|
||||
// Handle from transaction link click.
|
||||
const handleFromTransactionClick = (original) => {
|
||||
const { from_transaction_type, from_transaction_id } = original;
|
||||
|
||||
switch (from_transaction_type) {
|
||||
case 'Expense':
|
||||
openDrawer('expense-drawer', { expenseId: from_transaction_id });
|
||||
break;
|
||||
|
||||
case 'Bill':
|
||||
default:
|
||||
openDrawer('bill-drawer', { billId: from_transaction_id });
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={transactions}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onDelete: handleDeleteTransaction,
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="receipt-24" />}
|
||||
text={'Allocate landed cost'}
|
||||
onClick={handleAllocateCostClick}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
|
||||
<Card>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={transactions}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onDelete: handleDeleteTransaction,
|
||||
onFromTranscationClick: handleFromTransactionClick,
|
||||
}}
|
||||
className={'datatable--landed-cost-transactions'}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withAlertsActions)(LocatedLandedCostTable);
|
||||
export default compose(
|
||||
withAlertsActions,
|
||||
withDialogActions,
|
||||
withDrawerActions,
|
||||
)(LocatedLandedCostTable);
|
||||
|
||||
@@ -3,7 +3,6 @@ import intl from 'react-intl-universal';
|
||||
import { Intent, MenuItem, Menu } from '@blueprintjs/core';
|
||||
import { safeCallback } from 'utils';
|
||||
import { Icon } from 'components';
|
||||
|
||||
/**
|
||||
* Actions menu.
|
||||
*/
|
||||
@@ -20,22 +19,57 @@ export function ActionsMenu({ row: { original }, payload: { onDelete } }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function useLocatedLandedCostColumns() {
|
||||
return React.useMemo(() => [
|
||||
{
|
||||
Header: intl.get('name'),
|
||||
accessor: 'description',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
Header: intl.get('amount'),
|
||||
accessor: 'amount',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
Header: intl.get('allocation_method'),
|
||||
accessor: 'allocation_method',
|
||||
width: 100,
|
||||
},
|
||||
]);
|
||||
/**
|
||||
* From transaction table cell.
|
||||
*/
|
||||
export function FromTransactionCell({
|
||||
row: { original },
|
||||
payload: { onFromTranscationClick }
|
||||
}) {
|
||||
// Handle the link click
|
||||
const handleAnchorClick = () => {
|
||||
onFromTranscationClick && onFromTranscationClick(original);
|
||||
};
|
||||
|
||||
return (
|
||||
<a href="#" onClick={handleAnchorClick}>
|
||||
{original.from_transaction_type} → {original.from_transaction_id}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve bill located landed cost table columns.
|
||||
*/
|
||||
export function useLocatedLandedCostColumns() {
|
||||
return React.useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: intl.get('name'),
|
||||
accessor: 'description',
|
||||
width: 150,
|
||||
className: 'name',
|
||||
},
|
||||
{
|
||||
Header: intl.get('amount'),
|
||||
accessor: 'formatted_amount',
|
||||
width: 100,
|
||||
className: 'amount',
|
||||
},
|
||||
{
|
||||
id: 'from_transaction',
|
||||
Header: intl.get('From transaction'),
|
||||
Cell: FromTransactionCell,
|
||||
width: 100,
|
||||
className: 'from-transaction',
|
||||
},
|
||||
{
|
||||
Header: intl.get('allocation_method'),
|
||||
accessor: 'allocation_method_formatted',
|
||||
width: 100,
|
||||
className: 'allocation-method',
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'style/components/Drawers/ViewDetails.scss';
|
||||
|
||||
import { ExpenseDrawerProvider } from './ExpenseDrawerProvider';
|
||||
import ExpenseDrawerDetails from './ExpenseDrawerDetails';
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import ExpenseDrawerHeader from './ExpenseDrawerHeader';
|
||||
import ExpenseDrawerTable from './ExpenseDrawerTable';
|
||||
import ExpenseDrawerFooter from './ExpenseDrawerFooter';
|
||||
import { useExpenseDrawerContext } from './ExpenseDrawerProvider';
|
||||
import 'style/components/Drawer/ViewDetails.scss';
|
||||
|
||||
/**
|
||||
* Expense view details.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'style/components/Drawers/ViewDetails.scss';
|
||||
|
||||
import { ManualJournalDrawerProvider } from './ManualJournalDrawerProvider';
|
||||
import ManualJournalDrawerDetails from './ManualJournalDrawerDetails';
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ import ManualJournalDrawerFooter from './ManualJournalDrawerFooter';
|
||||
|
||||
import { useManualJournalDrawerContext } from 'containers/Drawers/ManualJournalDrawer/ManualJournalDrawerProvider';
|
||||
|
||||
import 'style/components/Drawer/ViewDetails.scss';
|
||||
|
||||
/**
|
||||
* Manual journal view details.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { useJournal } from 'hooks/query';
|
||||
import { DashboardInsider, DrawerHeaderContent } from 'components';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
const ManualJournalDrawerContext = React.createContext();
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ export default function ManualJournalDrawerTable({
|
||||
return (
|
||||
<div className="journal-drawer__content--table">
|
||||
<DataTable columns={columns} data={entries} />
|
||||
|
||||
<If condition={description}>
|
||||
<p className={'desc'}>
|
||||
<b>Description</b>: {description}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'style/components/Drawers/DrawerTemplate.scss';
|
||||
|
||||
import PaperTemplateHeader from './PaperTemplateHeader';
|
||||
import PaperTemplateTable from './PaperTemplateTable';
|
||||
import PaperTemplateFooter from './PaperTemplateFooter';
|
||||
import { updateItemsEntriesTotal } from 'containers/Entries/utils';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
import 'style/components/Drawer/DrawerTemplate.scss';
|
||||
|
||||
function PaperTemplate({ labels: propLabels, paperData, entries }) {
|
||||
const labels = {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'style/components/Drawers/DrawerTemplate.scss';
|
||||
|
||||
import PaymentPaperTemplateHeader from './PaymentPaperTemplateHeader';
|
||||
import PaymentPaperTemplateTable from './PaymentPaperTemplateTable';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
import 'style/components/Drawer/DrawerTemplate.scss';
|
||||
|
||||
export default function PaymentPaperTemplate({
|
||||
labels: propLabels,
|
||||
|
||||
@@ -30,6 +30,7 @@ function ItemsEntriesTable({
|
||||
linesNumber,
|
||||
currencyCode,
|
||||
itemType, // sellable or purchasable
|
||||
landedCost = false
|
||||
}) {
|
||||
const [rows, setRows] = React.useState(initialEntries);
|
||||
const [rowItem, setRowItem] = React.useState(null);
|
||||
@@ -94,7 +95,7 @@ function ItemsEntriesTable({
|
||||
}, [entries, rows]);
|
||||
|
||||
// Editiable items entries columns.
|
||||
const columns = useEditableItemsEntriesColumns();
|
||||
const columns = useEditableItemsEntriesColumns({ landedCost });
|
||||
|
||||
// Handles the editor data update.
|
||||
const handleUpdateData = useCallback(
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ItemsListCell,
|
||||
PercentFieldCell,
|
||||
NumericInputCell,
|
||||
CheckBoxFieldCell,
|
||||
} from 'components/DataTableCells';
|
||||
|
||||
/**
|
||||
@@ -90,27 +91,18 @@ export function IndexTableCell({ row: { index } }) {
|
||||
return <span>{index + 1}</span>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Landed cost cell.
|
||||
*/
|
||||
const LandedCostCell = ({
|
||||
row: { index },
|
||||
column: { id },
|
||||
cell: { value: initialValue },
|
||||
data,
|
||||
payload,
|
||||
}) => {
|
||||
return <Checkbox minimal={true} className="ml2" />;
|
||||
};
|
||||
|
||||
/**
|
||||
* Landed cost header cell.
|
||||
*/
|
||||
const LandedCostHeaderCell = () => {
|
||||
return (
|
||||
<>
|
||||
<T id={'cost'} />
|
||||
<Hint content={''} />
|
||||
<T id={'Landed'} />
|
||||
<Hint
|
||||
content={
|
||||
'This options allows you to be able to add additional cost eg. freight then allocate cost to the items in your bills.'
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -118,7 +110,7 @@ const LandedCostHeaderCell = () => {
|
||||
/**
|
||||
* Retrieve editable items entries columns.
|
||||
*/
|
||||
export function useEditableItemsEntriesColumns() {
|
||||
export function useEditableItemsEntriesColumns({ landedCost }) {
|
||||
return React.useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -182,14 +174,19 @@ export function useEditableItemsEntriesColumns() {
|
||||
width: 100,
|
||||
className: 'total',
|
||||
},
|
||||
{
|
||||
Header: '',
|
||||
accessor: 'landed_cost',
|
||||
Cell: LandedCostCell,
|
||||
width: 70,
|
||||
disableSortBy: true,
|
||||
disableResizing: true,
|
||||
},
|
||||
...(landedCost
|
||||
? [
|
||||
{
|
||||
Header: LandedCostHeaderCell,
|
||||
accessor: 'landed_cost',
|
||||
Cell: CheckBoxFieldCell,
|
||||
width: 100,
|
||||
disableSortBy: true,
|
||||
disableResizing: true,
|
||||
className: 'landed-cost',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
Header: '',
|
||||
accessor: 'action',
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
import { FastField } from 'formik';
|
||||
import React from 'react';
|
||||
import ExpenseFormEntriesTable from './ExpenseFormEntriesTable';
|
||||
import { defaultExpenseEntry } from './utils';
|
||||
import { useExpenseFormContext } from './ExpenseFormPageProvider';
|
||||
import { defaultExpenseEntry, accountsFieldShouldUpdate } from './utils';
|
||||
|
||||
/**
|
||||
* Expense form entries field.
|
||||
*/
|
||||
export default function ExpenseFormEntriesField({ linesNumber = 4 }) {
|
||||
// Expense form context.
|
||||
const { accounts } = useExpenseFormContext();
|
||||
|
||||
return (
|
||||
<FastField name={'categories'}>
|
||||
<FastField
|
||||
name={'categories'}
|
||||
accounts={accounts}
|
||||
shouldUpdate={accountsFieldShouldUpdate}
|
||||
>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
|
||||
@@ -22,12 +22,13 @@ export default function ExpenseFormEntriesTable({
|
||||
error,
|
||||
onChange,
|
||||
currencyCode,
|
||||
landedCost = true,
|
||||
}) {
|
||||
// Expense form context.
|
||||
const { accounts } = useExpenseFormContext();
|
||||
|
||||
// Memorized data table columns.
|
||||
const columns = useExpenseFormTableColumns();
|
||||
const columns = useExpenseFormTableColumns({ landedCost });
|
||||
|
||||
// Handles update datatable data.
|
||||
const handleUpdateData = useCallback(
|
||||
@@ -61,6 +62,7 @@ export default function ExpenseFormEntriesTable({
|
||||
|
||||
return (
|
||||
<DataTableEditable
|
||||
name={'expense-form'}
|
||||
columns={columns}
|
||||
data={entries}
|
||||
sticky={true}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
inputIntent,
|
||||
handleDateChange,
|
||||
} from 'utils';
|
||||
import { customersFieldShouldUpdate, accountsFieldShouldUpdate } from './utils';
|
||||
import {
|
||||
CurrencySelectList,
|
||||
ContactSelecetList,
|
||||
@@ -51,7 +52,11 @@ export default function ExpenseFormHeader() {
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<FastField name={'payment_account_id'}>
|
||||
<FastField
|
||||
name={'payment_account_id'}
|
||||
accounts={accounts}
|
||||
shouldUpdate={accountsFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'payment_account'} />}
|
||||
@@ -118,7 +123,11 @@ export default function ExpenseFormHeader() {
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<FastField name={'customer_id'}>
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
customers={customers}
|
||||
shouldUpdate={customersFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'customer'} />}
|
||||
|
||||
@@ -56,8 +56,12 @@ const ActionsCellRenderer = ({
|
||||
const LandedCostHeaderCell = () => {
|
||||
return (
|
||||
<>
|
||||
<T id={'cost'} />
|
||||
<Hint content={''} />
|
||||
<T id={'Landed'} />
|
||||
<Hint
|
||||
content={
|
||||
'This options allows you to be able to add additional cost eg. freight then allocate cost to the items in your bills.'
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -87,7 +91,7 @@ function ExpenseAccountFooterCell() {
|
||||
/**
|
||||
* Retrieve expense form table entries columns.
|
||||
*/
|
||||
export function useExpenseFormTableColumns() {
|
||||
export function useExpenseFormTableColumns({ landedCost }) {
|
||||
return React.useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -127,15 +131,19 @@ export function useExpenseFormTableColumns() {
|
||||
className: 'description',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
Header: LandedCostHeaderCell,
|
||||
accessor: 'landed_cost',
|
||||
Cell: CheckBoxFieldCell,
|
||||
disableSortBy: true,
|
||||
disableResizing: true,
|
||||
width: 70,
|
||||
className: 'landed_cost',
|
||||
},
|
||||
...(landedCost
|
||||
? [
|
||||
{
|
||||
Header: LandedCostHeaderCell,
|
||||
accessor: 'landed_cost',
|
||||
Cell: CheckBoxFieldCell,
|
||||
disableSortBy: true,
|
||||
disableResizing: true,
|
||||
width: 100,
|
||||
className: 'landed-cost',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
Header: '',
|
||||
accessor: 'action',
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { AppToaster } from 'components';
|
||||
import moment from 'moment';
|
||||
import intl from 'react-intl-universal';
|
||||
import { transformToForm, repeatValue } from 'utils';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
transformToForm,
|
||||
repeatValue,
|
||||
} from 'utils';
|
||||
|
||||
const ERROR = {
|
||||
EXPENSE_ALREADY_PUBLISHED: 'EXPENSE.ALREADY.PUBLISHED',
|
||||
@@ -27,7 +31,7 @@ export const defaultExpenseEntry = {
|
||||
amount: '',
|
||||
expense_account_id: '',
|
||||
description: '',
|
||||
landed_cost: 0,
|
||||
landed_cost: false,
|
||||
};
|
||||
|
||||
export const defaultExpense = {
|
||||
@@ -62,3 +66,23 @@ export const transformToEditForm = (
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmine cusotmers fast-field should update.
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmine accounts fast-field should update.
|
||||
*/
|
||||
export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FastField, Field, ErrorMessage } from 'formik';
|
||||
import { useFormikContext, FastField, Field, ErrorMessage } from 'formik';
|
||||
import {
|
||||
FormGroup,
|
||||
Classes,
|
||||
@@ -23,12 +23,21 @@ import withSettings from 'containers/Settings/withSettings';
|
||||
import { ACCOUNT_PARENT_TYPE } from 'common/accountTypes';
|
||||
|
||||
import { compose, inputIntent } from 'utils';
|
||||
import {
|
||||
sellDescriptionFieldShouldUpdate,
|
||||
sellAccountFieldShouldUpdate,
|
||||
sellPriceFieldShouldUpdate,
|
||||
costPriceFieldShouldUpdate,
|
||||
costAccountFieldShouldUpdate,
|
||||
purchaseDescFieldShouldUpdate,
|
||||
} from './utils';
|
||||
|
||||
/**
|
||||
* Item form body.
|
||||
*/
|
||||
function ItemFormBody({ baseCurrency }) {
|
||||
const { accounts } = useItemFormContext();
|
||||
const { values } = useFormikContext();
|
||||
|
||||
return (
|
||||
<div class="page-form__section page-form__section--selling-cost">
|
||||
@@ -53,7 +62,11 @@ function ItemFormBody({ baseCurrency }) {
|
||||
</FastField>
|
||||
|
||||
{/*------------- Selling price ------------- */}
|
||||
<FastField name={'sell_price'}>
|
||||
<FastField
|
||||
name={'sell_price'}
|
||||
sellable={values.sellable}
|
||||
shouldUpdate={sellPriceFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'selling_price'} />}
|
||||
@@ -78,7 +91,12 @@ function ItemFormBody({ baseCurrency }) {
|
||||
</FastField>
|
||||
|
||||
{/*------------- Selling account ------------- */}
|
||||
<FastField name={'sell_account_id'}>
|
||||
<FastField
|
||||
name={'sell_account_id'}
|
||||
sellable={values.sellable}
|
||||
accounts={accounts}
|
||||
shouldUpdate={sellAccountFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'account'} />}
|
||||
@@ -107,7 +125,11 @@ function ItemFormBody({ baseCurrency }) {
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<FastField name={'sell_description'}>
|
||||
<FastField
|
||||
name={'sell_description'}
|
||||
sellable={values.sellable}
|
||||
shouldUpdate={sellDescriptionFieldShouldUpdate}
|
||||
>
|
||||
{({ form: { values }, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'description'} />}
|
||||
@@ -146,7 +168,11 @@ function ItemFormBody({ baseCurrency }) {
|
||||
</FastField>
|
||||
|
||||
{/*------------- Cost price ------------- */}
|
||||
<FastField name={'cost_price'}>
|
||||
<FastField
|
||||
name={'cost_price'}
|
||||
purchasable={values.purchasable}
|
||||
shouldUpdate={costPriceFieldShouldUpdate}
|
||||
>
|
||||
{({ field, form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'cost_price'} />}
|
||||
@@ -171,7 +197,12 @@ function ItemFormBody({ baseCurrency }) {
|
||||
</FastField>
|
||||
|
||||
{/*------------- Cost account ------------- */}
|
||||
<FastField name={'cost_account_id'}>
|
||||
<FastField
|
||||
name={'cost_account_id'}
|
||||
purchasable={values.purchasable}
|
||||
accounts={accounts}
|
||||
shouldUpdate={costAccountFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'account'} />}
|
||||
@@ -200,7 +231,11 @@ function ItemFormBody({ baseCurrency }) {
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<FastField name={'purchase_description'}>
|
||||
<FastField
|
||||
name={'purchase_description'}
|
||||
purchasable={values.purchasable}
|
||||
shouldUpdate={purchaseDescFieldShouldUpdate}
|
||||
>
|
||||
{({ form: { values }, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'description'} />}
|
||||
|
||||
@@ -8,6 +8,7 @@ import classNames from 'classnames';
|
||||
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
|
||||
import { accountsFieldShouldUpdate } from './utils';
|
||||
import { compose, inputIntent } from 'utils';
|
||||
import { ACCOUNT_TYPE } from 'common/accountTypes';
|
||||
import { useItemFormContext } from './ItemFormProvider';
|
||||
@@ -27,7 +28,11 @@ function ItemFormInventorySection({ baseCurrency }) {
|
||||
<Row>
|
||||
<Col xs={6}>
|
||||
{/*------------- Inventory account ------------- */}
|
||||
<FastField name={'inventory_account_id'}>
|
||||
<FastField
|
||||
name={'inventory_account_id'}
|
||||
accounts={accounts}
|
||||
shouldUpdate={accountsFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { touched, error } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'inventory_account'} />}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { CLASSES } from 'common/classes';
|
||||
|
||||
import { useItemFormContext } from './ItemFormProvider';
|
||||
import { handleStringChange, inputIntent } from 'utils';
|
||||
import { categoriesFieldShouldUpdate } from './utils';
|
||||
|
||||
/**
|
||||
* Item form primary section.
|
||||
@@ -130,7 +131,11 @@ export default function ItemFormPrimarySection() {
|
||||
</FastField>
|
||||
|
||||
{/*----------- Item category ----------*/}
|
||||
<FastField name={'category_id'}>
|
||||
<FastField
|
||||
name={'category_id'}
|
||||
categories={itemsCategories}
|
||||
shouldUpdate={categoriesFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'category'} />}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { AppToaster } from 'components';
|
||||
import { defaultFastFieldShouldUpdate } from 'utils';
|
||||
|
||||
export const transitionItemTypeKeyToLabel = (itemTypeKey) => {
|
||||
const table = {
|
||||
@@ -28,7 +29,9 @@ export const handleDeleteErrors = (errors) => {
|
||||
)
|
||||
) {
|
||||
AppToaster.show({
|
||||
message: intl.get('you_could_not_delete_item_that_has_associated_inventory_adjustments_transacions'),
|
||||
message: intl.get(
|
||||
'you_could_not_delete_item_that_has_associated_inventory_adjustments_transacions',
|
||||
),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
@@ -38,8 +41,83 @@ export const handleDeleteErrors = (errors) => {
|
||||
)
|
||||
) {
|
||||
AppToaster.show({
|
||||
message: intl.get('cannot_change_item_type_to_inventory_with_item_has_associated_transactions'),
|
||||
message: intl.get(
|
||||
'cannot_change_item_type_to_inventory_with_item_has_associated_transactions',
|
||||
),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines accounts fast field should update.
|
||||
*/
|
||||
export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines categories fast field should update.
|
||||
*/
|
||||
export const categoriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.categories !== oldProps.categories ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sell price fast field should update.
|
||||
*/
|
||||
export const sellPriceFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.sellable !== oldProps.sellable ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sell account fast field should update.
|
||||
*/
|
||||
export const sellAccountFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
newProps.sellable !== oldProps.sellable ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sell description fast field should update.
|
||||
*/
|
||||
export const sellDescriptionFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.sellable !== oldProps.sellable ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
export const costAccountFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
newProps.purchasable !== oldProps.purchasable ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
export const costPriceFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.purchasable !== oldProps.purchasable ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
export const purchaseDescFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.purchasable !== oldProps.purchasable ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ function BillForm({
|
||||
currency_code: baseCurrency,
|
||||
}),
|
||||
}),
|
||||
[bill],
|
||||
[bill, baseCurrency],
|
||||
);
|
||||
|
||||
// Transform response error to fields.
|
||||
|
||||
@@ -7,6 +7,7 @@ import classNames from 'classnames';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { ContactSelecetList, FieldRequiredHint, Icon } from 'components';
|
||||
import { vendorsFieldShouldUpdate } from './utils';
|
||||
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
@@ -28,7 +29,11 @@ function BillFormHeader() {
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ------- Vendor name ------ */}
|
||||
<FastField name={'vendor_id'}>
|
||||
<FastField
|
||||
name={'vendor_id'}
|
||||
vendors={vendors}
|
||||
shouldUpdate={vendorsFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'vendor_name'} />}
|
||||
|
||||
@@ -4,13 +4,23 @@ import { FastField } from 'formik';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
import ItemsEntriesTable from 'containers/Entries/ItemsEntriesTable';
|
||||
import {
|
||||
entriesFieldShouldUpdate
|
||||
} from './utils';
|
||||
|
||||
/**
|
||||
* Bill form body.
|
||||
*/
|
||||
export default function BillFormBody({ defaultBill }) {
|
||||
const { items } = useBillFormContext();
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||
<FastField name={'entries'}>
|
||||
<FastField
|
||||
name={'entries'}
|
||||
items={items}
|
||||
shouldUpdate={entriesFieldShouldUpdate}
|
||||
>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
@@ -25,6 +35,7 @@ export default function BillFormBody({ defaultBill }) {
|
||||
errors={error}
|
||||
linesNumber={4}
|
||||
currencyCode={values.currency_code}
|
||||
landedCost={true}
|
||||
/>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
@@ -2,7 +2,11 @@ import moment from 'moment';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { AppToaster } from 'components';
|
||||
import { transformToForm, repeatValue } from 'utils';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
transformToForm,
|
||||
repeatValue,
|
||||
} from 'utils';
|
||||
|
||||
export const MIN_LINES_NUMBER = 4;
|
||||
|
||||
@@ -13,6 +17,7 @@ export const defaultBillEntry = {
|
||||
discount: '',
|
||||
quantity: '',
|
||||
description: '',
|
||||
landed_cost: false,
|
||||
};
|
||||
|
||||
export const defaultBill = {
|
||||
@@ -62,3 +67,23 @@ export const handleDeleteErrors = (errors) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines vendors fast field should update
|
||||
*/
|
||||
export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.vendors !== oldProps.vendors ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines entries fast field should update.
|
||||
*/
|
||||
export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.items !== oldProps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@ export function ActionsMenu({
|
||||
/>
|
||||
</If>
|
||||
<MenuItem
|
||||
// icon={<Icon icon="quick-payment-16" iconSize={16} />}
|
||||
icon={<Icon icon="receipt-24" iconSize={16} />}
|
||||
text={intl.get('allocate_landed_coast')}
|
||||
onClick={safeCallback(onAllocateLandedCost, original)}
|
||||
/>
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
fullAmountPaymentEntries,
|
||||
amountPaymentEntries,
|
||||
} from 'utils';
|
||||
import { accountsFieldShouldUpdate, vendorsFieldShouldUpdate } from './utils';
|
||||
|
||||
/**
|
||||
* Payment made form header fields.
|
||||
@@ -48,17 +49,14 @@ function PaymentMadeFormHeaderFields({ baseCurrency }) {
|
||||
} = useFormikContext();
|
||||
|
||||
// Payment made form context.
|
||||
const {
|
||||
vendors,
|
||||
accounts,
|
||||
isNewMode,
|
||||
setPaymentVendorId,
|
||||
} = usePaymentMadeFormContext();
|
||||
const { vendors, accounts, isNewMode, setPaymentVendorId } =
|
||||
usePaymentMadeFormContext();
|
||||
|
||||
// Sumation of payable full-amount.
|
||||
const payableFullAmount = useMemo(() => safeSumBy(entries, 'due_amount'), [
|
||||
entries,
|
||||
]);
|
||||
const payableFullAmount = useMemo(
|
||||
() => safeSumBy(entries, 'due_amount'),
|
||||
[entries],
|
||||
);
|
||||
|
||||
// Handle receive full-amount click.
|
||||
const handleReceiveFullAmountClick = () => {
|
||||
@@ -78,7 +76,11 @@ function PaymentMadeFormHeaderFields({ baseCurrency }) {
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ------------ Vendor name ------------ */}
|
||||
<FastField name={'vendor_id'}>
|
||||
<FastField
|
||||
name={'vendor_id'}
|
||||
vendors={vendors}
|
||||
shouldUpdate={vendorsFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'vendor_name'} />}
|
||||
@@ -157,7 +159,7 @@ function PaymentMadeFormHeaderFields({ baseCurrency }) {
|
||||
small={true}
|
||||
minimal={true}
|
||||
>
|
||||
<T id={'receive_full_amount'} /> (
|
||||
<T id={'receive_full_amount'} /> (
|
||||
<Money amount={payableFullAmount} currency={baseCurrency} />)
|
||||
</Button>
|
||||
</FormGroup>
|
||||
@@ -184,7 +186,11 @@ function PaymentMadeFormHeaderFields({ baseCurrency }) {
|
||||
</FastField>
|
||||
|
||||
{/* ------------ Payment account ------------ */}
|
||||
<FastField name={'payment_account_id'}>
|
||||
<FastField
|
||||
name={'payment_account_id'}
|
||||
accounts={accounts}
|
||||
shouldUpdate={accountsFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'payment_account'} />}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import moment from 'moment';
|
||||
import { safeSumBy, transformToForm } from 'utils';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
safeSumBy,
|
||||
transformToForm,
|
||||
} from 'utils';
|
||||
|
||||
export const ERRORS = {
|
||||
PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE',
|
||||
@@ -9,10 +13,10 @@ export const ERRORS = {
|
||||
export const defaultPaymentMadeEntry = {
|
||||
bill_id: '',
|
||||
payment_amount: '',
|
||||
currency_code:'',
|
||||
currency_code: '',
|
||||
id: null,
|
||||
due_amount: null,
|
||||
amount:''
|
||||
amount: '',
|
||||
};
|
||||
|
||||
// Default initial values of payment made.
|
||||
@@ -48,7 +52,26 @@ export const transformToNewPageEntries = (entries) => {
|
||||
return entries.map((entry) => ({
|
||||
...transformToForm(entry, defaultPaymentMadeEntry),
|
||||
payment_amount: '',
|
||||
currency_code:entry.currency_code,
|
||||
|
||||
currency_code: entry.currency_code,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines vendors fast field when update.
|
||||
*/
|
||||
export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.vendors !== oldProps.vendors ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines accounts fast field when update.
|
||||
*/
|
||||
export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ function EstimateFormHeader({
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||
<EstimateFormHeaderFields />
|
||||
|
||||
<PageFormBigNumber
|
||||
label={intl.get('amount')}
|
||||
amount={totalDueAmount}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
inputIntent,
|
||||
handleDateChange,
|
||||
} from 'utils';
|
||||
import { customersFieldShouldUpdate } from './utils';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import {
|
||||
@@ -67,7 +68,11 @@ function EstimateFormHeader({
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField name={'customer_id'}>
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
customers={customers}
|
||||
shouldUpdate={customersFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'customer_name'} />}
|
||||
@@ -170,7 +175,9 @@ function EstimateFormHeader({
|
||||
}}
|
||||
tooltip={true}
|
||||
tooltipProps={{
|
||||
content: <T id={'setting_your_auto_generated_estimate_number'}/>,
|
||||
content: (
|
||||
<T id={'setting_your_auto_generated_estimate_number'} />
|
||||
),
|
||||
position: Position.BOTTOM_LEFT,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -4,6 +4,7 @@ import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import ItemsEntriesTable from 'containers/Entries/ItemsEntriesTable';
|
||||
import { useEstimateFormContext } from './EstimateFormProvider';
|
||||
import { entriesFieldShouldUpdate } from './utils';
|
||||
|
||||
/**
|
||||
* Estimate form items entries editor.
|
||||
@@ -13,7 +14,11 @@ export default function EstimateFormItemsEntriesField() {
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||
<FastField name={'entries'}>
|
||||
<FastField
|
||||
name={'entries'}
|
||||
items={items}
|
||||
shouldUpdate={entriesFieldShouldUpdate}
|
||||
>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import React from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
import moment from 'moment';
|
||||
import { transactionNumber, repeatValue, transformToForm } from 'utils';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
transactionNumber,
|
||||
repeatValue,
|
||||
transformToForm,
|
||||
} from 'utils';
|
||||
|
||||
export const MIN_LINES_NUMBER = 4;
|
||||
|
||||
@@ -49,4 +54,24 @@ export const useObserveEstimateNoSettings = (prefix, nextNumber) => {
|
||||
const estimateNo = transactionNumber(prefix, nextNumber);
|
||||
setFieldValue('estimate_number', estimateNo);
|
||||
}, [setFieldValue, prefix, nextNumber]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines customers fast field when update.
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines entries fast field should update.
|
||||
*/
|
||||
export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.items !== oldProps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,7 +10,10 @@ import { FastField, Field, ErrorMessage } from 'formik';
|
||||
import { FormattedMessage as T } from 'components';
|
||||
import { momentFormatter, compose, tansformDateValue } from 'utils';
|
||||
import classNames from 'classnames';
|
||||
import { useObserveInvoiceNoSettings } from './utils';
|
||||
import {
|
||||
useObserveInvoiceNoSettings,
|
||||
customerNameFieldShouldUpdate,
|
||||
} from './utils';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import {
|
||||
ContactSelecetList,
|
||||
@@ -58,15 +61,16 @@ function InvoiceFormHeaderFields({
|
||||
};
|
||||
|
||||
// Syncs invoice number settings with form.
|
||||
useObserveInvoiceNoSettings(
|
||||
invoiceNumberPrefix,
|
||||
invoiceNextNumber,
|
||||
);
|
||||
useObserveInvoiceNoSettings(invoiceNumberPrefix, invoiceNextNumber);
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField name={'customer_id'}>
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
customers={customers}
|
||||
shouldUpdate={customerNameFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'customer_name'} />}
|
||||
@@ -168,7 +172,9 @@ function InvoiceFormHeaderFields({
|
||||
}}
|
||||
tooltip={true}
|
||||
tooltipProps={{
|
||||
content: <T id={'setting_your_auto_generated_invoice_number'}/>,
|
||||
content: (
|
||||
<T id={'setting_your_auto_generated_invoice_number'} />
|
||||
),
|
||||
position: Position.BOTTOM_LEFT,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -4,6 +4,7 @@ import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import ItemsEntriesTable from 'containers/Entries/ItemsEntriesTable';
|
||||
import { useInvoiceFormContext } from './InvoiceFormProvider';
|
||||
import { entriesFieldShouldUpdate } from './utils';
|
||||
|
||||
/**
|
||||
* Invoice items entries editor field.
|
||||
@@ -13,7 +14,11 @@ export default function InvoiceItemsEntriesEditorField() {
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||
<FastField name={'entries'}>
|
||||
<FastField
|
||||
name={'entries'}
|
||||
items={items}
|
||||
shouldUpdate={entriesFieldShouldUpdate}
|
||||
>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
|
||||
@@ -11,7 +11,7 @@ import { updateItemsEntriesTotal } from 'containers/Entries/utils';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
|
||||
import { orderingLinesIndexes } from 'utils';
|
||||
import { defaultFastFieldShouldUpdate } from 'utils';
|
||||
import intl from 'react-intl-universal';
|
||||
import { ERROR } from 'common/errors';
|
||||
import { AppToaster } from 'components';
|
||||
@@ -100,4 +100,18 @@ export const useObserveInvoiceNoSettings = (prefix, nextNumber) => {
|
||||
const invoiceNo = transactionNumber(prefix, nextNumber);
|
||||
setFieldValue('invoice_no', invoiceNo);
|
||||
}, [setFieldValue, prefix, nextNumber]);
|
||||
};
|
||||
};
|
||||
|
||||
export const customerNameFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.items !== oldProps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
} from 'components';
|
||||
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
|
||||
import { ACCOUNT_TYPE } from 'common/accountTypes';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
|
||||
@@ -41,6 +42,8 @@ import {
|
||||
useObservePaymentNoSettings,
|
||||
amountPaymentEntries,
|
||||
fullAmountPaymentEntries,
|
||||
customersFieldShouldUpdate,
|
||||
accountsFieldShouldUpdate,
|
||||
} from './utils';
|
||||
import { toSafeInteger } from 'lodash';
|
||||
|
||||
@@ -115,7 +118,11 @@ function PaymentReceiveHeaderFields({
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ------------- Customer name ------------- */}
|
||||
<FastField name={'customer_id'}>
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
customers={customers}
|
||||
shouldUpdate={customersFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'customer_name'} />}
|
||||
@@ -247,7 +254,11 @@ function PaymentReceiveHeaderFields({
|
||||
</FastField>
|
||||
|
||||
{/* ------------ Deposit account ------------ */}
|
||||
<FastField name={'deposit_account_id'}>
|
||||
<FastField
|
||||
name={'deposit_account_id'}
|
||||
accounts={accounts}
|
||||
shouldUpdate={accountsFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'deposit_to'} />}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import React from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
import moment from 'moment';
|
||||
import { transactionNumber, transformToForm, safeSumBy } from 'utils';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
transactionNumber,
|
||||
transformToForm,
|
||||
safeSumBy,
|
||||
} from 'utils';
|
||||
|
||||
// Default payment receive entry.
|
||||
export const defaultPaymentReceiveEntry = {
|
||||
@@ -99,3 +104,23 @@ export const useObservePaymentNoSettings = (prefix, nextNumber) => {
|
||||
setFieldValue('payment_receive_no', invoiceNo);
|
||||
}, [setFieldValue, prefix, nextNumber]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines the customers fast-field should update.
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines the accounts fast-field should update.
|
||||
*/
|
||||
export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,7 +28,11 @@ import {
|
||||
inputIntent,
|
||||
} from 'utils';
|
||||
import { useReceiptFormContext } from './ReceiptFormProvider';
|
||||
import { useObserveReceiptNoSettings } from './utils';
|
||||
import {
|
||||
accountsFieldShouldUpdate,
|
||||
customersFieldShouldUpdate,
|
||||
useObserveReceiptNoSettings,
|
||||
} from './utils';
|
||||
|
||||
/**
|
||||
* Receipt form header fields.
|
||||
@@ -70,7 +74,11 @@ function ReceiptFormHeader({
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
{/* ----------- Customer name ----------- */}
|
||||
<FastField name={'customer_id'}>
|
||||
<FastField
|
||||
name={'customer_id'}
|
||||
customers={customers}
|
||||
shouldUpdate={customersFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'customer_name'} />}
|
||||
@@ -94,7 +102,11 @@ function ReceiptFormHeader({
|
||||
</FastField>
|
||||
|
||||
{/* ----------- Deposit account ----------- */}
|
||||
<FastField name={'deposit_account_id'}>
|
||||
<FastField
|
||||
name={'deposit_account_id'}
|
||||
accounts={accounts}
|
||||
shouldUpdate={accountsFieldShouldUpdate}
|
||||
>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'deposit_account'} />}
|
||||
|
||||
@@ -4,13 +4,14 @@ import { FastField } from 'formik';
|
||||
import ItemsEntriesTable from 'containers/Entries/ItemsEntriesTable';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { useReceiptFormContext } from './ReceiptFormProvider';
|
||||
import { entriesFieldShouldUpdate } from './utils';
|
||||
|
||||
export default function ReceiptItemsEntriesEditor({ defaultReceipt }) {
|
||||
const { items } = useReceiptFormContext();
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||
<FastField name={'entries'}>
|
||||
<FastField name={'entries'} items={items} shouldUpdate={entriesFieldShouldUpdate}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import React from 'react';
|
||||
import { useFormikContext } from 'formik';
|
||||
import moment from 'moment';
|
||||
import { transactionNumber, repeatValue, transformToForm } from 'utils';
|
||||
import {
|
||||
defaultFastFieldShouldUpdate,
|
||||
transactionNumber,
|
||||
repeatValue,
|
||||
transformToForm,
|
||||
} from 'utils';
|
||||
|
||||
export const MIN_LINES_NUMBER = 4;
|
||||
|
||||
@@ -42,7 +47,6 @@ export const transformToEditForm = (receipt) => ({
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
export const useObserveReceiptNoSettings = (prefix, nextNumber) => {
|
||||
const { setFieldValue } = useFormikContext();
|
||||
|
||||
@@ -50,4 +54,34 @@ export const useObserveReceiptNoSettings = (prefix, nextNumber) => {
|
||||
const receiptNo = transactionNumber(prefix, nextNumber);
|
||||
setFieldValue('receipt_number', receiptNo);
|
||||
}, [setFieldValue, prefix, nextNumber]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines entries fast field should update.
|
||||
*/
|
||||
export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.items !== oldProps.items ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines accounts fast field should update.
|
||||
*/
|
||||
export const accountsFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.accounts !== oldProps.accounts ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines customers fast field should update.
|
||||
*/
|
||||
export const customersFieldShouldUpdate = (newProps, oldProps) => {
|
||||
return (
|
||||
newProps.customers !== oldProps.customers ||
|
||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user