mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
feat: invoice status.
This commit is contained in:
@@ -25,38 +25,38 @@ export default function InvoiceFloatingActions({
|
||||
onCancelClick,
|
||||
onClearClick,
|
||||
invoice,
|
||||
invoicePublished,
|
||||
isDelivered,
|
||||
}) {
|
||||
const { resetForm, submitForm } = useFormikContext();
|
||||
|
||||
const handleSubmitPublishBtnClick = (event) => {
|
||||
const handleSubmitDeliverBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: true,
|
||||
publish: true,
|
||||
delivered: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmitPublishAndNewBtnClick = (event) => {
|
||||
const handleSubmitDeliverAndNewBtnClick = (event) => {
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
publish: true,
|
||||
delivered: true,
|
||||
resetForm: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmitPublishContinueEditingBtnClick = (event) => {
|
||||
const handleSubmitDeliverContinueEditingBtnClick = (event) => {
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
publish: true,
|
||||
delivered: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmitDraftBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: true,
|
||||
publish: false,
|
||||
delivered: false,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -64,7 +64,7 @@ export default function InvoiceFloatingActions({
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
publish: false,
|
||||
delivered: false,
|
||||
resetForm: true,
|
||||
});
|
||||
};
|
||||
@@ -73,7 +73,7 @@ export default function InvoiceFloatingActions({
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
publish: false,
|
||||
delivered: false,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -88,26 +88,26 @@ export default function InvoiceFloatingActions({
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
|
||||
{/* ----------- Save And Publish ----------- */}
|
||||
<If condition={!invoice || !invoicePublished}>
|
||||
{/* ----------- Save And Deliver ----------- */}
|
||||
<If condition={!invoice || !isDelivered}>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
onClick={handleSubmitPublishBtnClick}
|
||||
text={<T id={'save_publish'} />}
|
||||
onClick={handleSubmitDeliverBtnClick}
|
||||
text={<T id={'save_and_deliver'} />}
|
||||
/>
|
||||
<Popover
|
||||
content={
|
||||
<Menu>
|
||||
<MenuItem
|
||||
text={<T id={'publish_and_new'} />}
|
||||
onClick={handleSubmitPublishAndNewBtnClick}
|
||||
text={<T id={'deliver_and_new'} />}
|
||||
onClick={handleSubmitDeliverAndNewBtnClick}
|
||||
/>
|
||||
<MenuItem
|
||||
text={<T id={'publish_continue_editing'} />}
|
||||
onClick={handleSubmitPublishContinueEditingBtnClick}
|
||||
text={<T id={'deliver_continue_editing'} />}
|
||||
onClick={handleSubmitDeliverContinueEditingBtnClick}
|
||||
/>
|
||||
</Menu>
|
||||
}
|
||||
@@ -156,13 +156,13 @@ export default function InvoiceFloatingActions({
|
||||
</ButtonGroup>
|
||||
</If>
|
||||
{/* ----------- Save and New ----------- */}
|
||||
<If condition={invoice && invoicePublished}>
|
||||
<If condition={invoice && isDelivered}>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
onClick={handleSubmitPublishBtnClick}
|
||||
onClick={handleSubmitDeliverBtnClick}
|
||||
text={<T id={'save'} />}
|
||||
/>
|
||||
<Popover
|
||||
@@ -170,7 +170,7 @@ export default function InvoiceFloatingActions({
|
||||
<Menu>
|
||||
<MenuItem
|
||||
text={<T id={'save_and_new'} />}
|
||||
onClick={handleSubmitPublishAndNewBtnClick}
|
||||
onClick={handleSubmitDeliverAndNewBtnClick}
|
||||
/>
|
||||
</Menu>
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Formik, Form } from 'formik';
|
||||
import moment from 'moment';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { pick, sumBy, omit } from 'lodash';
|
||||
import { pick, sumBy, omit, values } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
@@ -53,7 +53,7 @@ const defaultInitialValues = {
|
||||
customer_id: '',
|
||||
invoice_date: moment(new Date()).format('YYYY-MM-DD'),
|
||||
due_date: moment(new Date()).format('YYYY-MM-DD'),
|
||||
status: 'SEND',
|
||||
delivered: '',
|
||||
invoice_no: '',
|
||||
reference_no: '',
|
||||
invoice_message: '',
|
||||
@@ -170,6 +170,7 @@ function InvoiceForm({
|
||||
}
|
||||
const form = {
|
||||
...values,
|
||||
delivered: submitPayload.deliver,
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
|
||||
};
|
||||
// Handle the request success.
|
||||
@@ -262,7 +263,7 @@ function InvoiceForm({
|
||||
invoice={invoiceId}
|
||||
onCancelClick={handleCancelClick}
|
||||
onSubmitClick={handleSubmitClick}
|
||||
invoicePublished={true}
|
||||
isDelivered={values.delivered}
|
||||
/>
|
||||
</Form>
|
||||
)}
|
||||
|
||||
@@ -17,7 +17,7 @@ const Schema = Yup.object().shape({
|
||||
.max(DATATYPES_LENGTH.STRING)
|
||||
.label(formatMessage({ id: 'invoice_no_' })),
|
||||
reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING),
|
||||
status: Yup.string().required(),
|
||||
delivered: Yup.boolean().required(),
|
||||
invoice_message: Yup.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
|
||||
@@ -18,9 +18,16 @@ import { CLASSES } from 'common/classes';
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import { LoadingIndicator, Choose, DataTable, Money, Icon } from 'components';
|
||||
import {
|
||||
LoadingIndicator,
|
||||
Choose,
|
||||
If,
|
||||
DataTable,
|
||||
Money,
|
||||
Icon,
|
||||
} from 'components';
|
||||
import InvoicesEmptyStatus from './InvoicesEmptyStatus';
|
||||
|
||||
import { statusAccessor } from './components';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withViewDetails from 'containers/Views/withViewDetails';
|
||||
@@ -141,7 +148,7 @@ function InvoicesDataTable({
|
||||
{
|
||||
id: 'status',
|
||||
Header: formatMessage({ id: 'status' }),
|
||||
accessor: 'status',
|
||||
accessor: (row) => statusAccessor(row),
|
||||
width: 140,
|
||||
className: 'status',
|
||||
},
|
||||
|
||||
85
client/src/containers/Sales/Invoice/components.js
Normal file
85
client/src/containers/Sales/Invoice/components.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import React from 'react';
|
||||
import { Intent, Tag, ProgressBar } from '@blueprintjs/core';
|
||||
import { Choose, If, Icon } from 'components';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
|
||||
const calculateStatus = (paymentAmount, balanceAmount) =>
|
||||
paymentAmount / balanceAmount;
|
||||
|
||||
export const statusAccessor = (row) => {
|
||||
return (
|
||||
<div className={'status-accessor'}>
|
||||
<Choose>
|
||||
<Choose.When condition={row.is_delivered}>
|
||||
<Choose>
|
||||
<Choose.When condition={row.is_overdue && !row.is_partially_paid}>
|
||||
<span className={'overdue_status'}>
|
||||
<p>
|
||||
<T id={'overdue_by'} /> {row.overdue_days} <T id={'day'} />
|
||||
</p>
|
||||
</span>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.When condition={!row.is_overdue && row.is_partially_paid}>
|
||||
<div>
|
||||
<span>
|
||||
<p>
|
||||
<T id={'due_in'} /> {row.remaining_days}{' '}
|
||||
<T id={'day_partially_paid'} /> ${row.due_amount}{' '}
|
||||
<T id={'due'} />
|
||||
</p>
|
||||
</span>
|
||||
<ProgressBar
|
||||
animate={false}
|
||||
stripes={false}
|
||||
intent={Intent.PRIMARY}
|
||||
value={calculateStatus(row.payment_amount, row.balance)}
|
||||
/>
|
||||
</div>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.When condition={row.is_overdue && row.is_partially_paid}>
|
||||
<div>
|
||||
<span>
|
||||
<p>
|
||||
<T id={'overdue_by'} /> {row.overdue_days}{' '}
|
||||
<T id={'day_partially_paid'} /> ${row.due_amount}{' '}
|
||||
<T id={'due'} />
|
||||
</p>
|
||||
</span>
|
||||
<ProgressBar
|
||||
animate={false}
|
||||
stripes={false}
|
||||
intent={Intent.PRIMARY}
|
||||
value={calculateStatus(row.payment_amount, row.balance)}
|
||||
/>
|
||||
</div>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.When condition={row.is_fully_paid}>
|
||||
<span className={'fully-paid'}>
|
||||
<Icon icon="checkmark-16" iconSize={20} />
|
||||
</span>
|
||||
<span>
|
||||
<T id={'paid'} />
|
||||
</span>
|
||||
</Choose.When>
|
||||
<Choose.Otherwise>
|
||||
<span className={'remaining-status'}>
|
||||
<p>
|
||||
<T id={'due_in'} /> {row.remaining_days} <T id={'day'} />
|
||||
</p>
|
||||
</span>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<Tag minimal={true}>
|
||||
<T id={'draft'} />
|
||||
</Tag>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user