mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
feat: logic of excess amount confirmation
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Formik, Form } from 'formik';
|
import { Formik, Form, FormikHelpers } from 'formik';
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import { sumBy, defaultTo } from 'lodash';
|
import { sumBy, defaultTo } from 'lodash';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
transformToEditForm,
|
transformToEditForm,
|
||||||
transformErrors,
|
transformErrors,
|
||||||
transformFormToRequest,
|
transformFormToRequest,
|
||||||
|
getPaymentExcessAmountFromValues,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,6 +60,7 @@ function PaymentMadeForm({
|
|||||||
submitPayload,
|
submitPayload,
|
||||||
createPaymentMadeMutate,
|
createPaymentMadeMutate,
|
||||||
editPaymentMadeMutate,
|
editPaymentMadeMutate,
|
||||||
|
isExcessConfirmed,
|
||||||
} = usePaymentMadeFormContext();
|
} = usePaymentMadeFormContext();
|
||||||
|
|
||||||
// Form initial values.
|
// Form initial values.
|
||||||
@@ -81,13 +83,11 @@ function PaymentMadeForm({
|
|||||||
// Handle the form submit.
|
// Handle the form submit.
|
||||||
const handleSubmitForm = (
|
const handleSubmitForm = (
|
||||||
values,
|
values,
|
||||||
{ setSubmitting, resetForm, setFieldError },
|
{ setSubmitting, resetForm, setFieldError }: FormikHelpers<any>,
|
||||||
) => {
|
) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
// Total payment amount of entries.
|
|
||||||
const totalPaymentAmount = sumBy(values.entries, 'payment_amount');
|
|
||||||
|
|
||||||
if (totalPaymentAmount <= 0) {
|
if (values.amount <= 0) {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
message: intl.get('you_cannot_make_payment_with_zero_total_amount'),
|
message: intl.get('you_cannot_make_payment_with_zero_total_amount'),
|
||||||
intent: Intent.DANGER,
|
intent: Intent.DANGER,
|
||||||
@@ -95,6 +95,16 @@ function PaymentMadeForm({
|
|||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const excessAmount = getPaymentExcessAmountFromValues(values);
|
||||||
|
|
||||||
|
// Show the confirmation popup if the excess amount bigger than zero and
|
||||||
|
// has not been confirmed yet.
|
||||||
|
if (excessAmount > 0 && !isExcessConfirmed) {
|
||||||
|
openDialog('payment-made-excessed-payment');
|
||||||
|
setSubmitting(false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Transformes the form values to request body.
|
// Transformes the form values to request body.
|
||||||
const form = transformFormToRequest(values);
|
const form = transformFormToRequest(values);
|
||||||
|
|
||||||
@@ -124,11 +134,12 @@ function PaymentMadeForm({
|
|||||||
}
|
}
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isNewMode) {
|
if (!isNewMode) {
|
||||||
editPaymentMadeMutate([paymentMadeId, form]).then(onSaved).catch(onError);
|
return editPaymentMadeMutate([paymentMadeId, form])
|
||||||
|
.then(onSaved)
|
||||||
|
.catch(onError);
|
||||||
} else {
|
} else {
|
||||||
createPaymentMadeMutate(form).then(onSaved).catch(onError);
|
return createPaymentMadeMutate(form).then(onSaved).catch(onError);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
import {
|
import {
|
||||||
T,
|
T,
|
||||||
TotalLines,
|
TotalLines,
|
||||||
TotalLine,
|
TotalLine,
|
||||||
TotalLineBorderStyle,
|
TotalLineBorderStyle,
|
||||||
TotalLineTextStyle,
|
TotalLineTextStyle,
|
||||||
|
FormatNumber,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { usePaymentMadeTotals } from './utils';
|
import { usePaymentMadeExcessAmount, usePaymentMadeTotals } from './utils';
|
||||||
|
|
||||||
export function PaymentMadeFormFooterRight() {
|
export function PaymentMadeFormFooterRight() {
|
||||||
const { formattedSubtotal, formattedTotal } = usePaymentMadeTotals();
|
const { formattedSubtotal, formattedTotal } = usePaymentMadeTotals();
|
||||||
|
const excessAmount = usePaymentMadeExcessAmount();
|
||||||
|
const {
|
||||||
|
values: { currency_code: currencyCode },
|
||||||
|
} = useFormikContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PaymentMadeTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
<PaymentMadeTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||||
@@ -25,6 +31,11 @@ export function PaymentMadeFormFooterRight() {
|
|||||||
value={formattedTotal}
|
value={formattedTotal}
|
||||||
textStyle={TotalLineTextStyle.Bold}
|
textStyle={TotalLineTextStyle.Bold}
|
||||||
/>
|
/>
|
||||||
|
<TotalLine
|
||||||
|
title={'Excess Amount'}
|
||||||
|
value={<FormatNumber value={excessAmount} currency={currencyCode} />}
|
||||||
|
textStyle={TotalLineTextStyle.Regular}
|
||||||
|
/>
|
||||||
</PaymentMadeTotalLines>
|
</PaymentMadeTotalLines>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React, { useMemo } from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import { sumBy } from 'lodash';
|
|
||||||
import { CLASSES } from '@/constants/classes';
|
import { CLASSES } from '@/constants/classes';
|
||||||
import { Money, FormattedMessage as T } from '@/components';
|
import { Money, FormattedMessage as T } from '@/components';
|
||||||
|
|
||||||
import PaymentMadeFormHeaderFields from './PaymentMadeFormHeaderFields';
|
import PaymentMadeFormHeaderFields from './PaymentMadeFormHeaderFields';
|
||||||
|
import { usePaymentmadeTotalAmount } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment made header form.
|
* Payment made header form.
|
||||||
@@ -14,11 +14,10 @@ import PaymentMadeFormHeaderFields from './PaymentMadeFormHeaderFields';
|
|||||||
function PaymentMadeFormHeader() {
|
function PaymentMadeFormHeader() {
|
||||||
// Formik form context.
|
// Formik form context.
|
||||||
const {
|
const {
|
||||||
values: { entries, currency_code },
|
values: { currency_code },
|
||||||
} = useFormikContext();
|
} = useFormikContext();
|
||||||
|
|
||||||
// Calculate the payment amount of the entries.
|
const totalAmount = usePaymentmadeTotalAmount();
|
||||||
const amountPaid = useMemo(() => sumBy(entries, 'payment_amount'), [entries]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
@@ -31,7 +30,7 @@ function PaymentMadeFormHeader() {
|
|||||||
<T id={'amount_received'} />
|
<T id={'amount_received'} />
|
||||||
</span>
|
</span>
|
||||||
<h1 class="big-amount__number">
|
<h1 class="big-amount__number">
|
||||||
<Money amount={amountPaid} currency={currency_code} />
|
<Money amount={totalAmount} currency={currency_code} />
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
|
|||||||
const fullAmount = safeSumBy(newEntries, 'payment_amount');
|
const fullAmount = safeSumBy(newEntries, 'payment_amount');
|
||||||
|
|
||||||
setFieldValue('entries', newEntries);
|
setFieldValue('entries', newEntries);
|
||||||
setFieldValue('full_amount', fullAmount);
|
setFieldValue('amount', fullAmount);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handles the full-amount field blur.
|
// Handles the full-amount field blur.
|
||||||
@@ -129,14 +129,14 @@ function PaymentMadeFormHeaderFields({ organization: { base_currency } }) {
|
|||||||
className={('form-group--full-amount', Classes.FILL)}
|
className={('form-group--full-amount', Classes.FILL)}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
labelInfo={<Hint />}
|
labelInfo={<Hint />}
|
||||||
helperText={<ErrorMessage name="full_amount" />}
|
helperText={<ErrorMessage name="amount" />}
|
||||||
>
|
>
|
||||||
<ControlGroup>
|
<ControlGroup>
|
||||||
<InputPrependText text={currency_code} />
|
<InputPrependText text={currency_code} />
|
||||||
<MoneyInputGroup
|
<MoneyInputGroup
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setFieldValue('full_amount', value);
|
setFieldValue('amount', value);
|
||||||
}}
|
}}
|
||||||
onBlurValue={onFullAmountBlur}
|
onBlurValue={onFullAmountBlur}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
import { Features } from '@/constants';
|
import { Features } from '@/constants';
|
||||||
import { useFeatureCan } from '@/hooks/state';
|
import { useFeatureCan } from '@/hooks/state';
|
||||||
import {
|
import {
|
||||||
@@ -71,6 +71,8 @@ function PaymentMadeFormProvider({ query, paymentMadeId, ...props }) {
|
|||||||
|
|
||||||
const isFeatureLoading = isBranchesLoading;
|
const isFeatureLoading = isBranchesLoading;
|
||||||
|
|
||||||
|
const [isExcessConfirmed, setIsExcessConfirmed] = useState<boolean>(false);
|
||||||
|
|
||||||
// Provider payload.
|
// Provider payload.
|
||||||
const provider = {
|
const provider = {
|
||||||
paymentMadeId,
|
paymentMadeId,
|
||||||
@@ -98,6 +100,9 @@ function PaymentMadeFormProvider({ query, paymentMadeId, ...props }) {
|
|||||||
|
|
||||||
setSubmitPayload,
|
setSubmitPayload,
|
||||||
setPaymentVendorId,
|
setPaymentVendorId,
|
||||||
|
|
||||||
|
isExcessConfirmed,
|
||||||
|
setIsExcessConfirmed,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -23,14 +23,24 @@ const Schema = Yup.object().shape({
|
|||||||
const DEFAULT_ACCOUNT_SLUG = 'depreciation-expense';
|
const DEFAULT_ACCOUNT_SLUG = 'depreciation-expense';
|
||||||
|
|
||||||
function ExcessPaymentDialogContentRoot({ dialogName, closeDialog }) {
|
function ExcessPaymentDialogContentRoot({ dialogName, closeDialog }) {
|
||||||
const { setFieldValue } = useFormikContext();
|
const {
|
||||||
|
setFieldValue,
|
||||||
|
submitForm,
|
||||||
|
} = useFormikContext();
|
||||||
|
const { setIsExcessConfirmed } = usePaymentMadeFormContext();
|
||||||
|
|
||||||
const handleSubmit = (
|
const handleSubmit = (
|
||||||
values: ExcessPaymentValues,
|
values: ExcessPaymentValues,
|
||||||
{ setSubmitting }: FormikHelpers<ExcessPaymentValues>,
|
{ setSubmitting }: FormikHelpers<ExcessPaymentValues>,
|
||||||
) => {
|
) => {
|
||||||
closeDialog(dialogName);
|
|
||||||
setFieldValue(values.accountId);
|
setFieldValue(values.accountId);
|
||||||
|
setSubmitting(true);
|
||||||
|
setIsExcessConfirmed(true);
|
||||||
|
|
||||||
|
return submitForm().then(() => {
|
||||||
|
setSubmitting(false);
|
||||||
|
closeDialog(dialogName);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle close button click.
|
// Handle close button click.
|
||||||
@@ -66,7 +76,7 @@ interface ExcessPaymentDialogContentFormProps {
|
|||||||
function ExcessPaymentDialogContentForm({
|
function ExcessPaymentDialogContentForm({
|
||||||
onClose,
|
onClose,
|
||||||
}: ExcessPaymentDialogContentFormProps) {
|
}: ExcessPaymentDialogContentFormProps) {
|
||||||
const { submitForm } = useFormikContext();
|
const { submitForm, isSubmitting } = useFormikContext();
|
||||||
const { accounts } = usePaymentMadeFormContext();
|
const { accounts } = usePaymentMadeFormContext();
|
||||||
|
|
||||||
const handleCloseBtn = () => {
|
const handleCloseBtn = () => {
|
||||||
@@ -94,7 +104,11 @@ function ExcessPaymentDialogContentForm({
|
|||||||
|
|
||||||
<div className={Classes.DIALOG_FOOTER}>
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||||
<Button intent={Intent.PRIMARY} onClick={() => submitForm()}>
|
<Button
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
loading={isSubmitting}
|
||||||
|
onClick={() => submitForm()}
|
||||||
|
>
|
||||||
Continue to Payment
|
Continue to Payment
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleCloseBtn}>Cancel</Button>
|
<Button onClick={handleCloseBtn}>Cancel</Button>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const defaultPaymentMadeEntry = {
|
|||||||
|
|
||||||
// Default initial values of payment made.
|
// Default initial values of payment made.
|
||||||
export const defaultPaymentMade = {
|
export const defaultPaymentMade = {
|
||||||
full_amount: '',
|
amount: '',
|
||||||
vendor_id: '',
|
vendor_id: '',
|
||||||
payment_account_id: '',
|
payment_account_id: '',
|
||||||
payment_date: moment(new Date()).format('YYYY-MM-DD'),
|
payment_date: moment(new Date()).format('YYYY-MM-DD'),
|
||||||
@@ -53,10 +53,10 @@ export const defaultPaymentMade = {
|
|||||||
|
|
||||||
export const transformToEditForm = (paymentMade, paymentMadeEntries) => {
|
export const transformToEditForm = (paymentMade, paymentMadeEntries) => {
|
||||||
const attachments = transformAttachmentsToForm(paymentMade);
|
const attachments = transformAttachmentsToForm(paymentMade);
|
||||||
|
const appliedAmount = safeSumBy(paymentMadeEntries, 'payment_amount');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...transformToForm(paymentMade, defaultPaymentMade),
|
...transformToForm(paymentMade, defaultPaymentMade),
|
||||||
full_amount: safeSumBy(paymentMadeEntries, 'payment_amount'),
|
|
||||||
entries: [
|
entries: [
|
||||||
...paymentMadeEntries.map((paymentMadeEntry) => ({
|
...paymentMadeEntries.map((paymentMadeEntry) => ({
|
||||||
...transformToForm(paymentMadeEntry, defaultPaymentMadeEntry),
|
...transformToForm(paymentMadeEntry, defaultPaymentMadeEntry),
|
||||||
@@ -177,6 +177,30 @@ export const usePaymentMadeTotals = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const usePaymentmadeTotalAmount = () => {
|
||||||
|
const {
|
||||||
|
values: { amount },
|
||||||
|
} = useFormikContext();
|
||||||
|
|
||||||
|
return amount;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentMadeAppliedAmount = () => {
|
||||||
|
const {
|
||||||
|
values: { entries },
|
||||||
|
} = useFormikContext();
|
||||||
|
|
||||||
|
// Retrieves the invoice entries total.
|
||||||
|
return React.useMemo(() => sumBy(entries, 'payment_amount'), [entries]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentMadeExcessAmount = () => {
|
||||||
|
const appliedAmount = usePaymentMadeAppliedAmount();
|
||||||
|
const totalAmount = usePaymentmadeTotalAmount();
|
||||||
|
|
||||||
|
return Math.abs(totalAmount - appliedAmount);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines whether the bill has foreign customer.
|
* Detarmines whether the bill has foreign customer.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
@@ -191,3 +215,10 @@ export const usePaymentMadeIsForeignCustomer = () => {
|
|||||||
);
|
);
|
||||||
return isForeignCustomer;
|
return isForeignCustomer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getPaymentExcessAmountFromValues = (values) => {
|
||||||
|
const appliedAmount = sumBy(values.entries, 'payment_amount');
|
||||||
|
const totalAmount = values.amount;
|
||||||
|
|
||||||
|
return Math.abs(totalAmount - appliedAmount);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo, useRef } from 'react';
|
||||||
import { sumBy, isEmpty, defaultTo } from 'lodash';
|
import { sumBy, isEmpty, defaultTo } from 'lodash';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
@@ -37,6 +37,7 @@ import {
|
|||||||
transformFormToRequest,
|
transformFormToRequest,
|
||||||
transformErrors,
|
transformErrors,
|
||||||
resetFormState,
|
resetFormState,
|
||||||
|
getExceededAmountFromValues,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { PaymentReceiveSyncIncrementSettingsToForm } from './components';
|
import { PaymentReceiveSyncIncrementSettingsToForm } from './components';
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ function PaymentReceiveForm({
|
|||||||
organization: { base_currency },
|
organization: { base_currency },
|
||||||
|
|
||||||
// #withDialogActions
|
// #withDialogActions
|
||||||
openDialog
|
openDialog,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ function PaymentReceiveForm({
|
|||||||
submitPayload,
|
submitPayload,
|
||||||
editPaymentReceiveMutate,
|
editPaymentReceiveMutate,
|
||||||
createPaymentReceiveMutate,
|
createPaymentReceiveMutate,
|
||||||
|
isExcessConfirmed,
|
||||||
} = usePaymentReceiveFormContext();
|
} = usePaymentReceiveFormContext();
|
||||||
|
|
||||||
// Payment receive number.
|
// Payment receive number.
|
||||||
@@ -98,19 +100,21 @@ function PaymentReceiveForm({
|
|||||||
preferredDepositAccount,
|
preferredDepositAccount,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle form submit.
|
// Handle form submit.
|
||||||
const handleSubmitForm = (
|
const handleSubmitForm = (
|
||||||
values,
|
values,
|
||||||
{ setSubmitting, resetForm, setFieldError },
|
{ setSubmitting, resetForm, setFieldError },
|
||||||
) => {
|
) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
const exceededAmount = getExceededAmountFromValues(values);
|
||||||
|
|
||||||
if (true) {
|
// Show the confirm popup if the excessed amount bigger than zero and
|
||||||
|
// excess confirmation has not been confirmed yet.
|
||||||
|
if (exceededAmount > 0 && !isExcessConfirmed) {
|
||||||
|
setSubmitting(false);
|
||||||
openDialog('payment-received-excessed-payment');
|
openDialog('payment-received-excessed-payment');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformes the form values to request body.
|
// Transformes the form values to request body.
|
||||||
const form = transformFormToRequest(values);
|
const form = transformFormToRequest(values);
|
||||||
|
|
||||||
@@ -146,11 +150,11 @@ function PaymentReceiveForm({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (paymentReceiveId) {
|
if (paymentReceiveId) {
|
||||||
editPaymentReceiveMutate([paymentReceiveId, form])
|
return editPaymentReceiveMutate([paymentReceiveId, form])
|
||||||
.then(onSaved)
|
.then(onSaved)
|
||||||
.catch(onError);
|
.catch(onError);
|
||||||
} else {
|
} else {
|
||||||
createPaymentReceiveMutate(form).then(onSaved).catch(onError);
|
return createPaymentReceiveMutate(form).then(onSaved).catch(onError);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@@ -200,5 +204,5 @@ export default compose(
|
|||||||
preferredDepositAccount: paymentReceiveSettings?.preferredDepositAccount,
|
preferredDepositAccount: paymentReceiveSettings?.preferredDepositAccount,
|
||||||
})),
|
})),
|
||||||
withCurrentOrganization(),
|
withCurrentOrganization(),
|
||||||
withDialogActions
|
withDialogActions,
|
||||||
)(PaymentReceiveForm);
|
)(PaymentReceiveForm);
|
||||||
|
|||||||
@@ -7,11 +7,16 @@ import {
|
|||||||
TotalLine,
|
TotalLine,
|
||||||
TotalLineBorderStyle,
|
TotalLineBorderStyle,
|
||||||
TotalLineTextStyle,
|
TotalLineTextStyle,
|
||||||
|
FormatNumber,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { usePaymentReceiveTotals } from './utils';
|
import {
|
||||||
|
usePaymentReceiveTotals,
|
||||||
|
usePaymentReceivedTotalExceededAmount,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
export function PaymentReceiveFormFootetRight() {
|
export function PaymentReceiveFormFootetRight() {
|
||||||
const { formattedSubtotal, formattedTotal } = usePaymentReceiveTotals();
|
const { formattedSubtotal, formattedTotal } = usePaymentReceiveTotals();
|
||||||
|
const exceededAmount = usePaymentReceivedTotalExceededAmount();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PaymentReceiveTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
<PaymentReceiveTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||||
@@ -25,6 +30,11 @@ export function PaymentReceiveFormFootetRight() {
|
|||||||
value={formattedTotal}
|
value={formattedTotal}
|
||||||
textStyle={TotalLineTextStyle.Bold}
|
textStyle={TotalLineTextStyle.Bold}
|
||||||
/>
|
/>
|
||||||
|
<TotalLine
|
||||||
|
title={'Exceeded Amount'}
|
||||||
|
value={<FormatNumber value={exceededAmount} />}
|
||||||
|
textStyle={TotalLineTextStyle.Regular}
|
||||||
|
/>
|
||||||
</PaymentReceiveTotalLines>
|
</PaymentReceiveTotalLines>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,15 +30,9 @@ function PaymentReceiveFormHeader() {
|
|||||||
function PaymentReceiveFormBigTotal() {
|
function PaymentReceiveFormBigTotal() {
|
||||||
// Formik form context.
|
// Formik form context.
|
||||||
const {
|
const {
|
||||||
values: { currency_code, entries },
|
values: { currency_code, amount },
|
||||||
} = useFormikContext();
|
} = useFormikContext();
|
||||||
|
|
||||||
// Calculates the total payment amount from due amount.
|
|
||||||
const paymentFullAmount = useMemo(
|
|
||||||
() => sumBy(entries, 'payment_amount'),
|
|
||||||
[entries],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}>
|
||||||
<div class="big-amount">
|
<div class="big-amount">
|
||||||
@@ -46,7 +40,7 @@ function PaymentReceiveFormBigTotal() {
|
|||||||
<T id={'amount_received'} />
|
<T id={'amount_received'} />
|
||||||
</span>
|
</span>
|
||||||
<h1 class="big-amount__number">
|
<h1 class="big-amount__number">
|
||||||
<Money amount={paymentFullAmount} currency={currency_code} />
|
<Money amount={amount} currency={currency_code} />
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
import { Features } from '@/constants';
|
import { Features } from '@/constants';
|
||||||
import { useFeatureCan } from '@/hooks/state';
|
import { useFeatureCan } from '@/hooks/state';
|
||||||
import { DashboardInsider } from '@/components';
|
import { DashboardInsider } from '@/components';
|
||||||
@@ -74,6 +74,8 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
|
|||||||
const { mutateAsync: editPaymentReceiveMutate } = useEditPaymentReceive();
|
const { mutateAsync: editPaymentReceiveMutate } = useEditPaymentReceive();
|
||||||
const { mutateAsync: createPaymentReceiveMutate } = useCreatePaymentReceive();
|
const { mutateAsync: createPaymentReceiveMutate } = useCreatePaymentReceive();
|
||||||
|
|
||||||
|
const [isExcessConfirmed, setIsExcessConfirmed] = useState<boolean>(false);
|
||||||
|
|
||||||
// Provider payload.
|
// Provider payload.
|
||||||
const provider = {
|
const provider = {
|
||||||
paymentReceiveId,
|
paymentReceiveId,
|
||||||
@@ -97,6 +99,9 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
|
|||||||
|
|
||||||
editPaymentReceiveMutate,
|
editPaymentReceiveMutate,
|
||||||
createPaymentReceiveMutate,
|
createPaymentReceiveMutate,
|
||||||
|
|
||||||
|
isExcessConfirmed,
|
||||||
|
setIsExcessConfirmed,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
|
|||||||
import { AccountsSelect, FFormGroup } from '@/components';
|
import { AccountsSelect, FFormGroup } from '@/components';
|
||||||
import { usePaymentReceiveFormContext } from '../../PaymentReceiveFormProvider';
|
import { usePaymentReceiveFormContext } from '../../PaymentReceiveFormProvider';
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
|
import { usePaymentReceivedTotalExceededAmount } from '../../utils';
|
||||||
|
|
||||||
interface ExcessPaymentValues {
|
interface ExcessPaymentValues {
|
||||||
accountId: string;
|
accountId: string;
|
||||||
@@ -23,15 +24,23 @@ const Schema = Yup.object().shape({
|
|||||||
const DEFAULT_ACCOUNT_SLUG = 'depreciation-expense';
|
const DEFAULT_ACCOUNT_SLUG = 'depreciation-expense';
|
||||||
|
|
||||||
export function ExcessPaymentDialogContentRoot({ dialogName, closeDialog }) {
|
export function ExcessPaymentDialogContentRoot({ dialogName, closeDialog }) {
|
||||||
const { setFieldValue } = useFormikContext();
|
const { setFieldValue, submitForm } = useFormikContext();
|
||||||
|
const { setIsExcessConfirmed } = usePaymentReceiveFormContext();
|
||||||
const initialAccountId = useDefaultExcessPaymentDeposit();
|
const initialAccountId = useDefaultExcessPaymentDeposit();
|
||||||
|
const exceededAmount = usePaymentReceivedTotalExceededAmount();
|
||||||
|
|
||||||
const handleSubmit = (
|
const handleSubmit = (
|
||||||
values: ExcessPaymentValues,
|
values: ExcessPaymentValues,
|
||||||
{ setSubmitting }: FormikHelpers<ExcessPaymentValues>,
|
{ setSubmitting }: FormikHelpers<ExcessPaymentValues>,
|
||||||
) => {
|
) => {
|
||||||
closeDialog(dialogName);
|
setSubmitting(true);
|
||||||
|
setIsExcessConfirmed(true);
|
||||||
setFieldValue('unearned_revenue_account_id', values.accountId);
|
setFieldValue('unearned_revenue_account_id', values.accountId);
|
||||||
|
|
||||||
|
submitForm().then(() => {
|
||||||
|
closeDialog(dialogName);
|
||||||
|
setSubmitting(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
closeDialog(dialogName);
|
closeDialog(dialogName);
|
||||||
@@ -47,7 +56,10 @@ export function ExcessPaymentDialogContentRoot({ dialogName, closeDialog }) {
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<Form>
|
<Form>
|
||||||
<ExcessPaymentDialogContentForm onClose={handleClose} />
|
<ExcessPaymentDialogContentForm
|
||||||
|
exceededAmount={exceededAmount}
|
||||||
|
onClose={handleClose}
|
||||||
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
@@ -57,9 +69,9 @@ export const ExcessPaymentDialogContent = R.compose(withDialogActions)(
|
|||||||
ExcessPaymentDialogContentRoot,
|
ExcessPaymentDialogContentRoot,
|
||||||
);
|
);
|
||||||
|
|
||||||
function ExcessPaymentDialogContentForm({ onClose }) {
|
function ExcessPaymentDialogContentForm({ onClose, exceededAmount }) {
|
||||||
const { accounts } = usePaymentReceiveFormContext();
|
const { accounts } = usePaymentReceiveFormContext();
|
||||||
const { submitForm } = useFormikContext();
|
const { submitForm, isSubmitting } = useFormikContext();
|
||||||
|
|
||||||
const handleCloseBtn = () => {
|
const handleCloseBtn = () => {
|
||||||
onClose && onClose();
|
onClose && onClose();
|
||||||
@@ -69,8 +81,9 @@ function ExcessPaymentDialogContentForm({ onClose }) {
|
|||||||
<>
|
<>
|
||||||
<div className={Classes.DIALOG_BODY}>
|
<div className={Classes.DIALOG_BODY}>
|
||||||
<p>
|
<p>
|
||||||
Would you like to record the excess amount of $1000 as advanced
|
Would you like to record the excess amount of{' '}
|
||||||
payment from the customer.
|
<strong>{exceededAmount}</strong> as advanced payment from the
|
||||||
|
customer.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
@@ -87,7 +100,12 @@ function ExcessPaymentDialogContentForm({ onClose }) {
|
|||||||
|
|
||||||
<div className={Classes.DIALOG_FOOTER}>
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||||
<Button intent={Intent.PRIMARY} onClick={() => submitForm()}>
|
<Button
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
loading={isSubmitting}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
onClick={() => submitForm()}
|
||||||
|
>
|
||||||
Continue to Payment
|
Continue to Payment
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleCloseBtn}>Cancel</Button>
|
<Button onClick={handleCloseBtn}>Cancel</Button>
|
||||||
|
|||||||
@@ -250,6 +250,30 @@ export const usePaymentReceiveTotals = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const usePaymentReceivedTotalAppliedAmount = () => {
|
||||||
|
const {
|
||||||
|
values: { entries },
|
||||||
|
} = useFormikContext();
|
||||||
|
|
||||||
|
// Retrieves the invoice entries total.
|
||||||
|
return React.useMemo(() => sumBy(entries, 'payment_amount'), [entries]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentReceivedTotalAmount = () => {
|
||||||
|
const {
|
||||||
|
values: { amount },
|
||||||
|
} = useFormikContext();
|
||||||
|
|
||||||
|
return amount;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentReceivedTotalExceededAmount = () => {
|
||||||
|
const totalAmount = usePaymentReceivedTotalAmount();
|
||||||
|
const totalApplied = usePaymentReceivedTotalAppliedAmount();
|
||||||
|
|
||||||
|
return Math.abs(totalAmount - totalApplied);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines whether the payment has foreign customer.
|
* Detarmines whether the payment has foreign customer.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
@@ -274,3 +298,11 @@ export const resetFormState = ({ initialValues, values, resetForm }) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getExceededAmountFromValues = (values) => {
|
||||||
|
const totalApplied = sumBy(values.entries, 'payment_amount');
|
||||||
|
const totalAmount = values.amount;
|
||||||
|
|
||||||
|
return totalAmount - totalApplied;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user