feat: invoice status.

This commit is contained in:
elforjani3
2020-12-15 20:11:36 +02:00
parent 461e18f2a4
commit ff95008bc6
8 changed files with 200 additions and 69 deletions

View File

@@ -25,38 +25,38 @@ export default function InvoiceFloatingActions({
onCancelClick, onCancelClick,
onClearClick, onClearClick,
invoice, invoice,
invoicePublished, isDelivered,
}) { }) {
const { resetForm, submitForm } = useFormikContext(); const { resetForm, submitForm } = useFormikContext();
const handleSubmitPublishBtnClick = (event) => { const handleSubmitDeliverBtnClick = (event) => {
saveInvoke(onSubmitClick, event, { saveInvoke(onSubmitClick, event, {
redirect: true, redirect: true,
publish: true, delivered: true,
}); });
}; };
const handleSubmitPublishAndNewBtnClick = (event) => { const handleSubmitDeliverAndNewBtnClick = (event) => {
submitForm(); submitForm();
saveInvoke(onSubmitClick, event, { saveInvoke(onSubmitClick, event, {
redirect: false, redirect: false,
publish: true, delivered: true,
resetForm: true, resetForm: true,
}); });
}; };
const handleSubmitPublishContinueEditingBtnClick = (event) => { const handleSubmitDeliverContinueEditingBtnClick = (event) => {
submitForm(); submitForm();
saveInvoke(onSubmitClick, event, { saveInvoke(onSubmitClick, event, {
redirect: false, redirect: false,
publish: true, delivered: true,
}); });
}; };
const handleSubmitDraftBtnClick = (event) => { const handleSubmitDraftBtnClick = (event) => {
saveInvoke(onSubmitClick, event, { saveInvoke(onSubmitClick, event, {
redirect: true, redirect: true,
publish: false, delivered: false,
}); });
}; };
@@ -64,7 +64,7 @@ export default function InvoiceFloatingActions({
submitForm(); submitForm();
saveInvoke(onSubmitClick, event, { saveInvoke(onSubmitClick, event, {
redirect: false, redirect: false,
publish: false, delivered: false,
resetForm: true, resetForm: true,
}); });
}; };
@@ -73,7 +73,7 @@ export default function InvoiceFloatingActions({
submitForm(); submitForm();
saveInvoke(onSubmitClick, event, { saveInvoke(onSubmitClick, event, {
redirect: false, redirect: false,
publish: false, delivered: false,
}); });
}; };
@@ -88,26 +88,26 @@ export default function InvoiceFloatingActions({
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}> <div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
{/* ----------- Save And Publish ----------- */} {/* ----------- Save And Deliver ----------- */}
<If condition={!invoice || !invoicePublished}> <If condition={!invoice || !isDelivered}>
<ButtonGroup> <ButtonGroup>
<Button <Button
disabled={isSubmitting} disabled={isSubmitting}
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
type="submit" type="submit"
onClick={handleSubmitPublishBtnClick} onClick={handleSubmitDeliverBtnClick}
text={<T id={'save_publish'} />} text={<T id={'save_and_deliver'} />}
/> />
<Popover <Popover
content={ content={
<Menu> <Menu>
<MenuItem <MenuItem
text={<T id={'publish_and_new'} />} text={<T id={'deliver_and_new'} />}
onClick={handleSubmitPublishAndNewBtnClick} onClick={handleSubmitDeliverAndNewBtnClick}
/> />
<MenuItem <MenuItem
text={<T id={'publish_continue_editing'} />} text={<T id={'deliver_continue_editing'} />}
onClick={handleSubmitPublishContinueEditingBtnClick} onClick={handleSubmitDeliverContinueEditingBtnClick}
/> />
</Menu> </Menu>
} }
@@ -156,13 +156,13 @@ export default function InvoiceFloatingActions({
</ButtonGroup> </ButtonGroup>
</If> </If>
{/* ----------- Save and New ----------- */} {/* ----------- Save and New ----------- */}
<If condition={invoice && invoicePublished}> <If condition={invoice && isDelivered}>
<ButtonGroup> <ButtonGroup>
<Button <Button
disabled={isSubmitting} disabled={isSubmitting}
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
type="submit" type="submit"
onClick={handleSubmitPublishBtnClick} onClick={handleSubmitDeliverBtnClick}
text={<T id={'save'} />} text={<T id={'save'} />}
/> />
<Popover <Popover
@@ -170,7 +170,7 @@ export default function InvoiceFloatingActions({
<Menu> <Menu>
<MenuItem <MenuItem
text={<T id={'save_and_new'} />} text={<T id={'save_and_new'} />}
onClick={handleSubmitPublishAndNewBtnClick} onClick={handleSubmitDeliverAndNewBtnClick}
/> />
</Menu> </Menu>
} }

View File

@@ -3,7 +3,7 @@ import { Formik, Form } from 'formik';
import moment from 'moment'; import moment from 'moment';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { pick, sumBy, omit } from 'lodash'; import { pick, sumBy, omit, values } from 'lodash';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
@@ -53,7 +53,7 @@ const defaultInitialValues = {
customer_id: '', customer_id: '',
invoice_date: moment(new Date()).format('YYYY-MM-DD'), invoice_date: moment(new Date()).format('YYYY-MM-DD'),
due_date: moment(new Date()).format('YYYY-MM-DD'), due_date: moment(new Date()).format('YYYY-MM-DD'),
status: 'SEND', delivered: '',
invoice_no: '', invoice_no: '',
reference_no: '', reference_no: '',
invoice_message: '', invoice_message: '',
@@ -170,6 +170,7 @@ function InvoiceForm({
} }
const form = { const form = {
...values, ...values,
delivered: submitPayload.deliver,
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })), entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
}; };
// Handle the request success. // Handle the request success.
@@ -262,7 +263,7 @@ function InvoiceForm({
invoice={invoiceId} invoice={invoiceId}
onCancelClick={handleCancelClick} onCancelClick={handleCancelClick}
onSubmitClick={handleSubmitClick} onSubmitClick={handleSubmitClick}
invoicePublished={true} isDelivered={values.delivered}
/> />
</Form> </Form>
)} )}

View File

@@ -17,7 +17,7 @@ const Schema = Yup.object().shape({
.max(DATATYPES_LENGTH.STRING) .max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'invoice_no_' })), .label(formatMessage({ id: 'invoice_no_' })),
reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING), reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING),
status: Yup.string().required(), delivered: Yup.boolean().required(),
invoice_message: Yup.string() invoice_message: Yup.string()
.trim() .trim()
.min(1) .min(1)

View File

@@ -18,9 +18,16 @@ import { CLASSES } from 'common/classes';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; 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 InvoicesEmptyStatus from './InvoicesEmptyStatus';
import { statusAccessor } from './components';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withViewDetails from 'containers/Views/withViewDetails'; import withViewDetails from 'containers/Views/withViewDetails';
@@ -141,7 +148,7 @@ function InvoicesDataTable({
{ {
id: 'status', id: 'status',
Header: formatMessage({ id: 'status' }), Header: formatMessage({ id: 'status' }),
accessor: 'status', accessor: (row) => statusAccessor(row),
width: 140, width: 140,
className: 'status', className: 'status',
}, },

View 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>
);
};

View File

@@ -865,4 +865,15 @@ export default {
'The item categories has been deleted successfully .', 'The item categories has been deleted successfully .',
receivable_accounts_should_assign_with_customers: receivable_accounts_should_assign_with_customers:
'receivable accounts should assign with customers', 'receivable accounts should assign with customers',
delivered: 'Delivered',
save_and_deliver: 'Save and Deliver',
deliver_and_new: 'Deliver and new',
deliver_continue_editing: 'Deliver (continue editing)',
due_in: 'Due in',
day_partially_paid: 'Day Partially paid,',
due: 'Due.',
overdue_by: 'Overdue by',
day: 'day.',
day_partially_paid: 'Day Partially paid',
paid: 'Paid',
}; };

View File

@@ -292,68 +292,66 @@ export default {
path: [ path: [
'M16 9h-2.55V6h-2.9v3H8l4 4zm3-6H4.99C3.88 3 3 3.9 3 5v14c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5v-3h3.56c.69 1.19 1.97 2 3.45 2s2.75-.81 3.45-2H19v3zm0-5h-4.99c0 1.1-.9 2-2 2s-2-.9-2-2H5l-.01-9H19v9z', 'M16 9h-2.55V6h-2.9v3H8l4 4zm3-6H4.99C3.88 3 3 3.9 3 5v14c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5v-3h3.56c.69 1.19 1.97 2 3.45 2s2.75-.81 3.45-2H19v3zm0-5h-4.99c0 1.1-.9 2-2 2s-2-.9-2-2H5l-.01-9H19v9z',
], ],
viewBox: '0 0 24 24' viewBox: '0 0 24 24',
}, },
'arrow-drop-up-16': { 'arrow-drop-up-16': {
path: ['M7 14l5-5 5 5z'], path: ['M7 14l5-5 5 5z'],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
}, },
'date-range': { 'checkmark-16': {
path: ['M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z'], path: ['M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z'],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
}, },
'hash': { 'date-range': {
path: [
'M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z',
],
viewBox: '0 0 24 24',
},
hash: {
path: [ path: [
'M14.1683,13.45l.976-3.7971H10.0652L9.1144,13.45Zm2.0976,0H20.57l-.7427,2.1451H15.7281l-1.31,5.2292-2.1511.0208,1.3489-5.25h-5.04l-1.31,5.2292-2.1511.0208,1.35-5.25H2L2.7429,13.45H7.0154l.976-3.7971H3.4307l.7428-2.1451H8.544l1.15-4.4716L11.732,3,10.603,7.5074h5.0954l1.1454-4.4567L18.8864,3l-1.129,4.5072H22l-.7428,2.1451H17.22L16.2689,13.45Z', 'M14.1683,13.45l.976-3.7971H10.0652L9.1144,13.45Zm2.0976,0H20.57l-.7427,2.1451H15.7281l-1.31,5.2292-2.1511.0208,1.3489-5.25h-5.04l-1.31,5.2292-2.1511.0208,1.35-5.25H2L2.7429,13.45H7.0154l.976-3.7971H3.4307l.7428-2.1451H8.544l1.15-4.4716L11.732,3,10.603,7.5074h5.0954l1.1454-4.4567L18.8864,3l-1.129,4.5072H22l-.7428,2.1451H17.22L16.2689,13.45Z',
], ],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
}, },
"bookmark": { bookmark: {
path: [ path: ['M19 5H5v16l7-5 7 5V4z'],
'M19 5H5v16l7-5 7 5V4z',
],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
}, },
"person": { person: {
path: [ path: [
'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z', 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z',
], ],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
}, },
"info": { info: {
path: [ path: [
'M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z' 'M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z',
], ],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
}, },
"currency": { currency: {
path: [ path: [
'M10.9571,13.44a6.9356,6.9356,0,0,0,0-9.2751,4.8008,4.8008,0,1,1,0,9.2751Zm-5.156.1632a4.8008,4.8008,0,1,1,4.8008-4.8008A4.8008,4.8008,0,0,1,5.8011,13.603Z', 'M10.9571,13.44a6.9356,6.9356,0,0,0,0-9.2751,4.8008,4.8008,0,1,1,0,9.2751Zm-5.156.1632a4.8008,4.8008,0,1,1,4.8008-4.8008A4.8008,4.8008,0,0,1,5.8011,13.603Z',
], ],
viewBox: '0 0 18 18', viewBox: '0 0 18 18',
}, },
"short-text-16": { 'short-text-16': {
path: [ path: ['M13.6668,7H2V5H13.6668Zm-5.5862,2h-6v2h6Z'],
'M13.6668,7H2V5H13.6668Zm-5.5862,2h-6v2h6Z',
],
viewBox: '0 0 16 16', viewBox: '0 0 16 16',
}, },
"tag-16": { 'tag-16': {
path: [ path: ['M14,4v9H5L2,8.5,5,4Z'],
"M14,4v9H5L2,8.5,5,4Z",
],
viewBox: '0 0 16 16', viewBox: '0 0 16 16',
}, },
"payments": { payments: {
path: [ path: [
'M19 14V6c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zm-9-1c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm13-6v11c0 1.1-.9 2-2 2H4v-2h17V7h2z', 'M19 14V6c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zm-9-1c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm13-6v11c0 1.1-.9 2-2 2H4v-2h17V7h2z',
], ],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
}, },
"arrow-left": { 'arrow-left': {
path: [ path: ['M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z'],
'M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z',
],
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
} },
}; };

View File

@@ -1,46 +1,75 @@
.dashboard__insider--invoice-form{ .dashboard__insider--invoice-form {
background-color: #FFF; background-color: #fff;
} }
.page-form--invoice{ .page-form--invoice {
$self: '.page-form'; $self: '.page-form';
#{$self}__header{ #{$self}__header {
display: flex; display: flex;
&-fields{ &-fields {
flex: 1 0 0; flex: 1 0 0;
} }
.bp3-label{ .bp3-label {
min-width: 140px; min-width: 140px;
} }
.bp3-form-content{ .bp3-form-content {
width: 100%; width: 100%;
} }
.bp3-form-group{ .bp3-form-group {
margin-bottom: 18px; margin-bottom: 18px;
&.bp3-inline{ &.bp3-inline {
max-width: 440px; max-width: 440px;
} }
} }
.col--invoice-date{ .col--invoice-date {
max-width: 435px; max-width: 435px;
} }
} }
#{$self}__footer{ #{$self}__footer {
.form-group--invoice_message, .form-group--invoice_message,
.form-group--terms_conditions{ .form-group--terms_conditions {
max-width: 450px; max-width: 450px;
width: 100%; width: 100%;
textarea{ textarea {
width: 100%; width: 100%;
min-height: 60px; min-height: 60px;
} }
} }
} }
} }
.status-accessor {
span > p {
font-size: 13px;
font-weight: 400;
line-height: 1.5;
}
.fully-paid {
display: inline-block;
border-radius: 50%;
background: #2ba01d;
color: #ffffff;
margin-right: 6px;
}
.bp3-progress-bar {
background: rgba(92, 112, 128, 0.2);
border-radius: 40px;
display: block;
height: 6px;
overflow: hidden;
position: relative;
width: 80%;
}
}
.overdue-status {
}
.remaining-status {
}