Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ahmed Bouhuolia
2020-10-27 16:12:08 +02:00
24 changed files with 417 additions and 94 deletions

View File

@@ -11,7 +11,8 @@ import JournalNumberDialog from 'containers/Dialogs/JournalNumberDialog';
import BillNumberDialog from 'containers/Dialogs/BillNumberDialog'; import BillNumberDialog from 'containers/Dialogs/BillNumberDialog';
import PaymentNumberDialog from 'containers/Dialogs/PaymentNumberDialog'; import PaymentNumberDialog from 'containers/Dialogs/PaymentNumberDialog';
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog'; import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
export default function DialogsContainer() { export default function DialogsContainer() {
return ( return (
<div> <div>
@@ -20,6 +21,8 @@ export default function DialogsContainer() {
<BillNumberDialog dialogName={'bill-number-form'} /> <BillNumberDialog dialogName={'bill-number-form'} />
<PaymentNumberDialog dialogName={'payment-number-form'} /> <PaymentNumberDialog dialogName={'payment-number-form'} />
<EstimateNumberDialog dialogName={'estimate-number-form'} /> <EstimateNumberDialog dialogName={'estimate-number-form'} />
<ReceiptNumberDialog dialogName={'receipt-number-form'} />
<InvoiceNumberDialog dialogName={'invoice-number-form'} />
</div> </div>
); );
} }

View File

@@ -0,0 +1,74 @@
import React from 'react';
import { DialogContent } from 'components';
import { useQuery, queryCache } from 'react-query';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import withSettings from 'containers/Settings/withSettings';
import { compose, optionsMapToArray } from 'utils';
/**
* invoice number dialog's content.
*/
function InvoiceNumberDialogContent({
// #withSettings
nextNumber,
numberPrefix,
// #withSettingsActions
requestFetchOptions,
requestSubmitOptions,
// #withDialogActions
closeDialog,
}) {
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => {
return { key: option.key, ...option, group: 'sales_invoices' };
});
requestSubmitOptions({ options })
.then(() => {
setSubmitting(false);
closeDialog('invoice-number-form');
setTimeout(() => {
queryCache.invalidateQueries('settings');
}, 250);
})
.catch(() => {
setSubmitting(false);
});
};
const handleClose = () => {
closeDialog('invoice-number-form');
};
return (
<DialogContent isLoading={fetchSettings.isFetching}>
<ReferenceNumberForm
initialNumber={nextNumber}
initialPrefix={numberPrefix}
onSubmit={handleSubmitForm}
onClose={handleClose}
/>
</DialogContent>
);
}
export default compose(
withDialogActions,
withSettingsActions,
withSettings(({ invoiceSettings }) => ({
nextNumber: invoiceSettings?.next_number,
numberPrefix: invoiceSettings?.number_prefix,
})),
) (InvoiceNumberDialogContent);

View File

@@ -0,0 +1,27 @@
import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'utils';
const InvoiceNumberDialogContent = lazy(() =>
import('./InvoiceNumberDialogContent'),
);
function InvoiceNumberDialog({ dialogName, payload = { id: null }, isOpen }) {
return (
<Dialog
title={<T id={'bill_number_settings'} />}
name={dialogName}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
>
<DialogSuspense>
<InvoiceNumberDialogContent InvoiceNumberId={payload.id} />
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(InvoiceNumberDialog);

View File

@@ -0,0 +1,73 @@
import React from 'react';
import { DialogContent } from 'components';
import { useQuery, queryCache } from 'react-query';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import withSettings from 'containers/Settings/withSettings';
import { compose, optionsMapToArray } from 'utils';
/**
* Receipt number dialog's content.
*/
function ReceiptNumberDialogContent({
// #withSettings
nextNumber,
numberPrefix,
// #withSettingsActions
requestFetchOptions,
requestSubmitOptions,
// #withDialogActions
closeDialog,
}) {
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => {
return { key: option.key, ...option, group: 'sales_receipts' };
});
requestSubmitOptions({ options })
.then(() => {
setSubmitting(false);
closeDialog('receipt-number-form');
setTimeout(() => {
queryCache.invalidateQueries('settings');
}, 250);
})
.catch(() => {
setSubmitting(false);
});
};
const handleClose = () => {
closeDialog('receipt-number-form');
};
return (
<DialogContent isLoading={fetchSettings.isFetching}>
<ReferenceNumberForm
initialNumber={nextNumber}
initialPrefix={numberPrefix}
onSubmit={handleSubmitForm}
onClose={handleClose}
/>
</DialogContent>
);
}
export default compose(
withDialogActions,
withSettingsActions,
withSettings(({ receiptSettings }) => ({
nextNumber: receiptSettings?.next_number,
numberPrefix: receiptSettings?.number_prefix,
})),
)(ReceiptNumberDialogContent);

View File

@@ -0,0 +1,27 @@
import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'utils';
const ReceiptNumberDialogContent = lazy(() =>
import('./ReceiptNumberDialogContent'),
);
function ReceiptNumberDialog({ dialogName, paylaod = { id: null }, isOpen }) {
return (
<Dialog
name={dialogName}
title={<T id={'receipt_number_settings'} />}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
>
<DialogSuspense>
<ReceiptNumberDialogContent ReceiptNumberId={paylaod.id} />
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(ReceiptNumberDialog);

View File

@@ -21,6 +21,7 @@ import withInvoiceActions from './withInvoiceActions';
import withInvoiceDetail from './withInvoiceDetail'; import withInvoiceDetail from './withInvoiceDetail';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withMediaActions from 'containers/Media/withMediaActions'; import withMediaActions from 'containers/Media/withMediaActions';
import withSettings from 'containers/Settings/withSettings';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import Dragzone from 'components/Dragzone'; import Dragzone from 'components/Dragzone';
@@ -41,7 +42,10 @@ function InvoiceForm({
//#withDashboard //#withDashboard
changePageTitle, changePageTitle,
changePageSubtitle,
// #withSettings
invoiceNextNumber,
invoiceNumberPrefix,
//#withInvoiceDetail //#withInvoiceDetail
invoice, invoice,
@@ -91,7 +95,7 @@ function InvoiceForm({
due_date: Yup.date() due_date: Yup.date()
.required() .required()
.label(formatMessage({ id: 'due_date_' })), .label(formatMessage({ id: 'due_date_' })),
invoice_no: Yup.number() invoice_no: Yup.string()
.required() .required()
.label(formatMessage({ id: 'invoice_no_' })), .label(formatMessage({ id: 'invoice_no_' })),
reference_no: Yup.string().min(1).max(255), reference_no: Yup.string().min(1).max(255),
@@ -142,13 +146,17 @@ function InvoiceForm({
[], [],
); );
const invoiceNumber = invoiceNumberPrefix
? `${invoiceNumberPrefix}-${invoiceNextNumber}`
: invoiceNextNumber;
const defaultInitialValues = useMemo( const defaultInitialValues = useMemo(
() => ({ () => ({
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', status: 'SEND',
invoice_no: '', invoice_no: invoiceNumber,
reference_no: '', reference_no: '',
invoice_message: '', invoice_message: '',
terms_conditions: '', terms_conditions: '',
@@ -198,7 +206,6 @@ function InvoiceForm({
}, [invoice]); }, [invoice]);
const formik = useFormik({ const formik = useFormik({
enableReinitialize: true,
validationSchema, validationSchema,
initialValues: { initialValues: {
...initialValues, ...initialValues,
@@ -219,9 +226,12 @@ function InvoiceForm({
requestEditInvoice(invoice.id, requestForm) requestEditInvoice(invoice.id, requestForm)
.then((response) => { .then((response) => {
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage(
id: 'the_invoice_has_been_successfully_edited', {
}), id: 'the_invoice_has_been_successfully_edited',
},
{ number: values.invoice_no },
),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
setSubmitting(false); setSubmitting(false);
@@ -251,6 +261,11 @@ function InvoiceForm({
} }
}, },
}); });
useEffect(() => {
formik.setFieldValue('invoice_no', invoiceNumber);
}, [invoiceNumber]);
const handleSubmitClick = useCallback( const handleSubmitClick = useCallback(
(payload) => { (payload) => {
setPayload(payload); setPayload(payload);
@@ -349,4 +364,9 @@ export default compose(
withDashboardActions, withDashboardActions,
withMediaActions, withMediaActions,
withInvoiceDetail(), withInvoiceDetail(),
withSettings(({ invoiceSettings }) => ({
invoiceNextNumber: invoiceSettings?.next_number,
invoiceNumberPrefix: invoiceSettings?.number_prefix,
})),
)(InvoiceForm); )(InvoiceForm);

View File

@@ -13,15 +13,24 @@ import { Row, Col } from 'react-grid-system';
import moment from 'moment'; import moment from 'moment';
import { momentFormatter, compose, tansformDateValue } from 'utils'; import { momentFormatter, compose, tansformDateValue } from 'utils';
import classNames from 'classnames'; import classNames from 'classnames';
import { ListSelect, ErrorMessage, FieldRequiredHint, Hint } from 'components'; import {
ListSelect,
ErrorMessage,
FieldRequiredHint,
Icon,
InputPrependButton,
} from 'components';
import withCustomers from 'containers/Customers/withCustomers'; import withCustomers from 'containers/Customers/withCustomers';
import withDialogActions from 'containers/Dialog/withDialogActions';
function InvoiceFormHeader({ function InvoiceFormHeader({
formik: { errors, touched, setFieldValue, getFieldProps, values }, formik: { errors, touched, setFieldValue, getFieldProps, values },
//#withCustomers //#withCustomers
customers, customers,
//#withDialogActions
openDialog,
}) { }) {
const handleDateChange = useCallback( const handleDateChange = useCallback(
(date_filed) => (date) => { (date_filed) => (date) => {
@@ -67,6 +76,10 @@ function InvoiceFormHeader({
[setFieldValue], [setFieldValue],
); );
const handleInvoiceNumberChange = useCallback(() => {
openDialog('invoice-number-form', {});
}, [openDialog]);
return ( return (
<div class="page-form page-form--invoice"> <div class="page-form page-form--invoice">
<div className={'page-form__primary-section'}> <div className={'page-form__primary-section'}>
@@ -175,4 +188,5 @@ export default compose(
withCustomers(({ customers }) => ({ withCustomers(({ customers }) => ({
customers, customers,
})), })),
withDialogActions,
)(InvoiceFormHeader); )(InvoiceFormHeader);

View File

@@ -46,15 +46,15 @@ function InvoiceList({
changePageTitle(formatMessage({ id: 'invoice_list' })); changePageTitle(formatMessage({ id: 'invoice_list' }));
}, [changePageTitle, formatMessage]); }, [changePageTitle, formatMessage]);
const fetchResourceViews = useQuery( // const fetchResourceViews = useQuery(
['resource-views', 'sales_invoices'], // ['resource-views', 'sales_invoices'],
(key, resourceName) => requestFetchResourceViews(resourceName), // (key, resourceName) => requestFetchResourceViews(resourceName),
); // );
const fetchResourceFields = useQuery( // const fetchResourceFields = useQuery(
['resource-fields', 'sales_invoices'], // ['resource-fields', 'sales_invoices'],
(key, resourceName) => requestFetchResourceFields(resourceName), // (key, resourceName) => requestFetchResourceFields(resourceName),
); // );
const fetchInvoices = useQuery(['invoices-table', invoicesTableQuery], () => const fetchInvoices = useQuery(['invoices-table', invoicesTableQuery], () =>
requestFetchInvoiceTable(), requestFetchInvoiceTable(),
@@ -124,7 +124,7 @@ function InvoiceList({
); );
return ( return (
<DashboardInsider <DashboardInsider
loading={fetchResourceViews.isFetching || fetchResourceFields.isFetching} // loading={fetchResourceViews.isFetching || fetchResourceFields.isFetching}
name={'sales_invoices'} name={'sales_invoices'}
> >
<InvoiceActionsBar <InvoiceActionsBar

View File

@@ -2,7 +2,6 @@ import React, { useEffect, useCallback, useState, useMemo } from 'react';
import { import {
Intent, Intent,
Button, Button,
Classes,
Popover, Popover,
Menu, Menu,
MenuItem, MenuItem,
@@ -95,9 +94,13 @@ function InvoicesDataTable({
const actionMenuList = useCallback( const actionMenuList = useCallback(
(invoice) => ( (invoice) => (
<Menu> <Menu>
<MenuItem text={formatMessage({ id: 'view_details' })} /> <MenuItem
icon={<Icon icon="reader-18" />}
text={formatMessage({ id: 'view_details' })}
/>
<MenuDivider /> <MenuDivider />
<MenuItem <MenuItem
icon={<Icon icon="pen-18" />}
text={formatMessage({ id: 'edit_invoice' })} text={formatMessage({ id: 'edit_invoice' })}
onClick={handleEditInvoice(invoice)} onClick={handleEditInvoice(invoice)}
/> />

View File

@@ -24,7 +24,7 @@ import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import withResourceDetail from 'containers/Resources/withResourceDetails'; import withResourceDetail from 'containers/Resources/withResourceDetails';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withReceiptActions from './withReceipActions'; import withReceiptActions from './withReceiptActions';
import withReceipts from './withReceipts'; import withReceipts from './withReceipts';
import { compose } from 'utils'; import { compose } from 'utils';

View File

@@ -18,10 +18,11 @@ import ReceiptFromHeader from './ReceiptFormHeader';
import EstimatesItemsTable from 'containers/Sales/Estimate/EntriesItemsTable'; import EstimatesItemsTable from 'containers/Sales/Estimate/EntriesItemsTable';
import ReceiptFormFooter from './ReceiptFormFooter'; import ReceiptFormFooter from './ReceiptFormFooter';
import withReceipActions from './withReceipActions'; import withReceiptActions from './withReceiptActions';
import withReceiptDetail from './withReceiptDetail'; import withReceiptDetail from './withReceiptDetail';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withMediaActions from 'containers/Media/withMediaActions'; import withMediaActions from 'containers/Media/withMediaActions';
import withSettings from 'containers/Settings/withSettings';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import Dragzone from 'components/Dragzone'; import Dragzone from 'components/Dragzone';
@@ -45,7 +46,10 @@ function ReceiptForm({
//#withDashboard //#withDashboard
changePageTitle, changePageTitle,
changePageSubtitle,
// #withSettings
receiptNextNumber,
receiptNumberPrefix,
//#own Props //#own Props
receiptId, receiptId,
@@ -90,9 +94,9 @@ function ReceiptForm({
receipt_date: Yup.date() receipt_date: Yup.date()
.required() .required()
.label(formatMessage({ id: 'receipt_date_' })), .label(formatMessage({ id: 'receipt_date_' })),
// receipt_no: Yup.number() receipt_number: Yup.string()
// .required() .required()
// .label(formatMessage({ id: 'receipt_no_' })), .label(formatMessage({ id: 'receipt_no_' })),
deposit_account_id: Yup.number() deposit_account_id: Yup.number()
.required() .required()
.label(formatMessage({ id: 'deposit_account_' })), .label(formatMessage({ id: 'deposit_account_' })),
@@ -102,7 +106,7 @@ function ReceiptForm({
.min(1) .min(1)
.max(1024) .max(1024)
.label(formatMessage({ id: 'receipt_message_' })), .label(formatMessage({ id: 'receipt_message_' })),
email_send_to: Yup.string().email().nullable(), send_to_email: Yup.string().email().nullable(),
statement: Yup.string() statement: Yup.string()
.trim() .trim()
.min(1) .min(1)
@@ -143,12 +147,17 @@ function ReceiptForm({
[], [],
); );
const receiptNumber = receiptNumberPrefix
? `${receiptNumberPrefix}-${receiptNextNumber}`
: receiptNextNumber;
const defaultInitialValues = useMemo( const defaultInitialValues = useMemo(
() => ({ () => ({
customer_id: '', customer_id: '',
deposit_account_id: '', deposit_account_id: '',
receipt_number: receiptNumber,
receipt_date: moment(new Date()).format('YYYY-MM-DD'), receipt_date: moment(new Date()).format('YYYY-MM-DD'),
email_send_to: '', send_to_email: '',
reference_no: '', reference_no: '',
receipt_message: '', receipt_message: '',
statement: '', statement: '',
@@ -198,7 +207,6 @@ function ReceiptForm({
}, [receipt]); }, [receipt]);
const formik = useFormik({ const formik = useFormik({
enableReinitialize: true,
validationSchema, validationSchema,
initialValues: { initialValues: {
...initialValues, ...initialValues,
@@ -217,9 +225,12 @@ function ReceiptForm({
if (receipt && receipt.id) { if (receipt && receipt.id) {
requestEditReceipt(receipt.id, requestForm).then(() => { requestEditReceipt(receipt.id, requestForm).then(() => {
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage(
id: 'the_receipt_has_been_successfully_edited', {
}), id: 'the_receipt_has_been_successfully_edited',
},
{ number: values.receipt_number },
),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
setSubmitting(false); setSubmitting(false);
@@ -230,9 +241,12 @@ function ReceiptForm({
requestSubmitReceipt(requestForm) requestSubmitReceipt(requestForm)
.then((response) => { .then((response) => {
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage(
id: 'the_receipt_has_been_successfully_created', {
}), id: 'the_receipt_has_been_successfully_created',
},
{ number: values.receipt_number },
),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
setSubmitting(false); setSubmitting(false);
@@ -245,7 +259,6 @@ function ReceiptForm({
} }
}, },
}); });
console.log(formik.errors, 'ERROR');
const handleDeleteFile = useCallback( const handleDeleteFile = useCallback(
(_deletedFiles) => { (_deletedFiles) => {
@@ -287,6 +300,10 @@ function ReceiptForm({
); );
}; };
useEffect(() => {
formik.setFieldValue('receipt_number', receiptNumber);
}, [receiptNumber]);
return ( return (
<div className={'receipt-form'}> <div className={'receipt-form'}>
<form onSubmit={formik.handleSubmit}> <form onSubmit={formik.handleSubmit}>
@@ -342,8 +359,12 @@ function ReceiptForm({
} }
export default compose( export default compose(
withReceipActions, withReceiptActions,
withDashboardActions, withDashboardActions,
withMediaActions, withMediaActions,
withReceiptDetail(), withReceiptDetail(),
withSettings(({ receiptSettings }) => ({
receiptNextNumber: receiptSettings?.nextNumber,
receiptNumberPrefix: receiptSettings?.numberPrefix,
})),
)(ReceiptForm); )(ReceiptForm);

View File

@@ -18,11 +18,13 @@ import {
ListSelect, ListSelect,
ErrorMessage, ErrorMessage,
FieldRequiredHint, FieldRequiredHint,
Hint, Icon,
InputPrependButton,
} from 'components'; } from 'components';
import withCustomers from 'containers/Customers/withCustomers'; import withCustomers from 'containers/Customers/withCustomers';
import withAccounts from 'containers/Accounts/withAccounts'; import withAccounts from 'containers/Accounts/withAccounts';
import withDialogActions from 'containers/Dialog/withDialogActions';
function ReceiptFormHeader({ function ReceiptFormHeader({
formik: { errors, touched, setFieldValue, getFieldProps, values }, formik: { errors, touched, setFieldValue, getFieldProps, values },
@@ -31,6 +33,8 @@ function ReceiptFormHeader({
customers, customers,
//#withAccouts //#withAccouts
accountsList, accountsList,
//#withDialogActions
openDialog,
}) { }) {
const handleDateChange = useCallback( const handleDateChange = useCallback(
(date) => { (date) => {
@@ -82,6 +86,10 @@ function ReceiptFormHeader({
[accountsList], [accountsList],
); );
const handleReceiptNumberChange = useCallback(() => {
openDialog('receipt-number-form', {});
}, [openDialog]);
return ( return (
<div class="page-form receipt-form"> <div class="page-form receipt-form">
<div class="page-form__primary-section"> <div class="page-form__primary-section">
@@ -162,20 +170,39 @@ function ReceiptFormHeader({
</FormGroup> </FormGroup>
</div> </div>
{/* receipt_no */} {/* receipt_no */}
{/* <FormGroup <FormGroup
label={<T id={'receipt'} />} label={<T id={'receipt'} />}
inline={true} inline={true}
className={('form-group--receipt_no', Classes.FILL)} className={('form-group--receipt_number', Classes.FILL)}
labelInfo={<FieldRequiredHint />} labelInfo={<FieldRequiredHint />}
intent={errors.receipt_no && touched.receipt_no && Intent.DANGER} intent={
helperText={<ErrorMessage name="receipt_no" {...{ errors, touched }} />} errors.receipt_number && touched.receipt_number && Intent.DANGER
}
helperText={
<ErrorMessage name="receipt_number" {...{ errors, touched }} />
}
> >
<InputGroup <InputGroup
intent={errors.receipt_no && touched.receipt_no && Intent.DANGER} intent={
errors.receipt_number && touched.receipt_number && Intent.DANGER
}
minimal={true} minimal={true}
{...getFieldProps('receipt_no')} rightElement={
<InputPrependButton
buttonProps={{
onClick: handleReceiptNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: 'Setting your auto-generated receipt number',
position: Position.BOTTOM_LEFT,
}}
/>
}
{...getFieldProps('receipt_number')}
/> />
</FormGroup> */} </FormGroup>
{/*- Reference -*/} {/*- Reference -*/}
<FormGroup <FormGroup
@@ -197,12 +224,12 @@ function ReceiptFormHeader({
label={<T id={'send_to_email'} />} label={<T id={'send_to_email'} />}
inline={true} inline={true}
className={classNames('form-group--send_to_email', Classes.FILL)} className={classNames('form-group--send_to_email', Classes.FILL)}
intent={errors.email_send_to && touched.email_send_to && Intent.DANGER} intent={errors.send_to_email && touched.send_to_email && Intent.DANGER}
helperText={<ErrorMessage name="reference" {...{ errors, touched }} />} helperText={<ErrorMessage name="reference" {...{ errors, touched }} />}
> >
<InputGroup <InputGroup
intent={ intent={
errors.email_send_to && touched.email_send_to && Intent.DANGER errors.send_to_email && touched.send_to_email && Intent.DANGER
} }
minimal={true} minimal={true}
{...getFieldProps('send_to_email')} {...getFieldProps('send_to_email')}
@@ -219,4 +246,5 @@ export default compose(
withAccounts(({ accountsList }) => ({ withAccounts(({ accountsList }) => ({
accountsList, accountsList,
})), })),
withDialogActions,
)(ReceiptFormHeader); )(ReceiptFormHeader);

View File

@@ -15,7 +15,7 @@ import ReceiptViewTabs from './ReceiptViewTabs';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withResourceActions from 'containers/Resources/withResourcesActions'; import withResourceActions from 'containers/Resources/withResourcesActions';
import withReceipts from './withReceipts'; import withReceipts from './withReceipts';
import withReceipActions from './withReceipActions'; import withReceiptActions from './withReceiptActions';
import withViewsActions from 'containers/Views/withViewsActions'; import withViewsActions from 'containers/Views/withViewsActions';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -46,15 +46,15 @@ function ReceiptList({
requestFetchReceiptsTable(), requestFetchReceiptsTable(),
); );
const fetchResourceViews = useQuery( // const fetchResourceViews = useQuery(
['resource-views', 'sales_receipts'], // ['resource-views', 'sales_receipts'],
(key, resourceName) => requestFetchResourceViews(resourceName), // (key, resourceName) => requestFetchResourceViews(resourceName),
); // );
const fetchResourceFields = useQuery( // const fetchResourceFields = useQuery(
['resource-fields', 'sales_receipts'], // ['resource-fields', 'sales_receipts'],
(key, resourceName) => requestFetchResourceFields(resourceName), // (key, resourceName) => requestFetchResourceFields(resourceName),
); // );
useEffect(() => { useEffect(() => {
changePageTitle(formatMessage({ id: 'receipt_list' })); changePageTitle(formatMessage({ id: 'receipt_list' }));
@@ -140,7 +140,7 @@ function ReceiptList({
return ( return (
<DashboardInsider <DashboardInsider
name={'sales_receipts'} name={'sales_receipts'}
loading={fetchResourceViews.isFetching || fetchResourceFields.isFetching} // loading={fetchResourceViews.isFetching || fetchResourceFields.isFetching}
> >
<DashboardPageContent> <DashboardPageContent>
<ReceiptActionsBar <ReceiptActionsBar
@@ -182,7 +182,7 @@ function ReceiptList({
export default compose( export default compose(
withResourceActions, withResourceActions,
withReceipActions, withReceiptActions,
withDashboardActions, withDashboardActions,
withViewsActions, withViewsActions,
withReceipts(({ receiptTableQuery }) => ({ withReceipts(({ receiptTableQuery }) => ({

View File

@@ -9,7 +9,7 @@ import { DashboardViewsTabs } from 'components';
import { useUpdateEffect } from 'hooks'; import { useUpdateEffect } from 'hooks';
import withReceipts from './withReceipts'; import withReceipts from './withReceipts';
import withReceiptActions from './withReceipActions'; import withReceiptActions from './withReceiptActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withViewDetails from 'containers/Views/withViewDetails'; import withViewDetails from 'containers/Views/withViewDetails';

View File

@@ -8,7 +8,8 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import withCustomersActions from 'containers/Customers/withCustomersActions'; import withCustomersActions from 'containers/Customers/withCustomersActions';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withItemsActions from 'containers/Items/withItemsActions'; import withItemsActions from 'containers/Items/withItemsActions';
import withReceipActions from './withReceipActions'; import withReceiptActions from './withReceiptActions';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -24,6 +25,9 @@ function Receipts({
//#withReceiptsActions //#withReceiptsActions
requestFetchReceipt, requestFetchReceipt,
// #withSettingsActions
requestFetchOptions,
}) { }) {
const history = useHistory(); const history = useHistory();
const { id } = useParams(); const { id } = useParams();
@@ -44,6 +48,8 @@ function Receipts({
// Handle fetch Items data table or list // Handle fetch Items data table or list
const fetchItems = useQuery('items-table', () => requestFetchItems({})); const fetchItems = useQuery('items-table', () => requestFetchItems({}));
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
const handleFormSubmit = useCallback( const handleFormSubmit = useCallback(
(payload) => { (payload) => {
payload.redirect && history.push('/receipts'); payload.redirect && history.push('/receipts');
@@ -75,8 +81,9 @@ function Receipts({
} }
export default compose( export default compose(
withReceipActions, withReceiptActions,
withCustomersActions, withCustomersActions,
withItemsActions, withItemsActions,
withAccountsActions, withAccountsActions,
withSettingsActions,
)(Receipts); )(Receipts);

View File

@@ -24,7 +24,7 @@ import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withViewDetails from 'containers/Views/withViewDetails'; import withViewDetails from 'containers/Views/withViewDetails';
import withReceipts from './withReceipts'; import withReceipts from './withReceipts';
import withReceipActions from './withReceipActions'; import withReceiptActions from './withReceiptActions';
import withCurrentView from 'containers/Views/withCurrentView'; import withCurrentView from 'containers/Views/withCurrentView';
function ReceiptsDataTable({ function ReceiptsDataTable({
@@ -94,9 +94,13 @@ function ReceiptsDataTable({
const actionMenuList = useCallback( const actionMenuList = useCallback(
(estimate) => ( (estimate) => (
<Menu> <Menu>
<MenuItem text={formatMessage({ id: 'view_details' })} /> <MenuItem
icon={<Icon icon="reader-18" />}
text={formatMessage({ id: 'view_details' })}
/>
<MenuDivider /> <MenuDivider />
<MenuItem <MenuItem
icon={<Icon icon="pen-18" />}
text={formatMessage({ id: 'edit_receipt' })} text={formatMessage({ id: 'edit_receipt' })}
onClick={handleEditReceipt(estimate)} onClick={handleEditReceipt(estimate)}
/> />
@@ -134,6 +138,13 @@ function ReceiptsDataTable({
width: 140, width: 140,
className: 'customer_id', className: 'customer_id',
}, },
{
id: 'receipt_number',
Header: formatMessage({ id: 'receipt_number' }),
accessor: (row) => `#${row.receipt_number}`,
width: 140,
className: 'receipt_number',
},
{ {
id: 'deposit_account_id', id: 'deposit_account_id',
Header: formatMessage({ id: 'deposit_account' }), Header: formatMessage({ id: 'deposit_account' }),
@@ -142,11 +153,11 @@ function ReceiptsDataTable({
className: 'deposit_account', className: 'deposit_account',
}, },
{ {
id: 'email_send_to', id: 'send_to_email',
Header: formatMessage({ id: 'email' }), Header: formatMessage({ id: 'email' }),
accessor: 'email_send_to', accessor: 'send_to_email',
width: 140, width: 140,
className: 'email_send_to', className: 'send_to_email',
}, },
{ {
id: 'amount', id: 'amount',
@@ -229,7 +240,7 @@ export default compose(
withCurrentView, withCurrentView,
withDialogActions, withDialogActions,
withDashboardActions, withDashboardActions,
withReceipActions, withReceiptActions,
withReceipts( withReceipts(
({ ({
receiptsCurrentPage, receiptsCurrentPage,

View File

@@ -8,6 +8,8 @@ export default (mapState) => {
billsettings: state.settings.data.bills, billsettings: state.settings.data.bills,
billPaymentSettings: state.settings.data.billPayments, billPaymentSettings: state.settings.data.billPayments,
estimatesSettings: state.settings.data.salesEstimates, estimatesSettings: state.settings.data.salesEstimates,
receiptSettings: state.settings.data.salesReceipts,
invoiceSettings: state.settings.data.salesInvoices,
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -645,9 +645,9 @@ export default {
select_deposit_account: 'Select Deposit Account', select_deposit_account: 'Select Deposit Account',
once_delete_this_receipt_you_will_able_to_restore_it: `Once you delete this receipt, you won\'t be able to restore it later. Are you sure you want to delete this receipt?`, once_delete_this_receipt_you_will_able_to_restore_it: `Once you delete this receipt, you won\'t be able to restore it later. Are you sure you want to delete this receipt?`,
the_receipt_has_been_successfully_created: the_receipt_has_been_successfully_created:
'The recepit has been successfully created.', 'The recepit #{number} has been successfully created.',
the_receipt_has_been_successfully_edited: the_receipt_has_been_successfully_edited:
'The receipt has been successfully edited.', 'The receipt #{number} has been successfully edited.',
the_receipt_has_been_successfully_deleted: the_receipt_has_been_successfully_deleted:
'The receipt has been successfully deleted.', 'The receipt has been successfully deleted.',
bill_list: 'Bill List', bill_list: 'Bill List',
@@ -776,8 +776,11 @@ export default {
bigger_or_equals: 'Bigger or equals', bigger_or_equals: 'Bigger or equals',
prefix: 'Prefix', prefix: 'Prefix',
next_number: 'Next Number', next_number: 'Next Number',
journal_number_settings: 'Journal number Settings', journal_number_settings: 'Journal Number Settings',
bill_number_settings: 'Bill number Settings', bill_number_settings: 'Bill Number Settings',
payment_number_settings: 'Payment number Settings', payment_number_settings: 'Payment Number Settings',
Estimate_number_settings: 'Estimate Number Settings', Estimate_number_settings: 'Estimate Number Settings',
receipt_number_settings: 'Receipt Number Settings',
invoice_number_settings: 'Invoice Number Settings',
receipt_number: 'Receipt Number',
}; };

View File

@@ -67,8 +67,8 @@ export const fetchInvoicesTable = ({ query } = {}) => {
dispatch({ dispatch({
type: t.INVOICES_PAGE_SET, type: t.INVOICES_PAGE_SET,
payload: { payload: {
sales_invoices: response.data.sales_invoices.results, sales_invoices: response.data.sales_invoices,
pagination: response.data.sales_invoices.pagination, pagination: response.data.pagination,
customViewId: response.data.customViewId || -1, customViewId: response.data.customViewId || -1,
}, },
}); });
@@ -76,13 +76,13 @@ export const fetchInvoicesTable = ({ query } = {}) => {
dispatch({ dispatch({
type: t.INVOICES_ITEMS_SET, type: t.INVOICES_ITEMS_SET,
payload: { payload: {
sales_invoices: response.data.sales_invoices.results, sales_invoices: response.data.sales_invoices,
}, },
}); });
dispatch({ dispatch({
type: t.INVOICES_PAGINATION_SET, type: t.INVOICES_PAGINATION_SET,
payload: { payload: {
pagination: response.data.sales_invoices.pagination, pagination: response.data.pagination,
customViewId: response.data.customViewId || -1, customViewId: response.data.customViewId || -1,
}, },
}); });

View File

@@ -80,7 +80,7 @@ const reducer = createReducer(initialState, {
const { pagination, customViewId } = action.payload; const { pagination, customViewId } = action.payload;
const mapped = { const mapped = {
pageSize: parseInt(pagination.pageSize, 10), pageSize: parseInt(pagination.page_size, 10),
page: parseInt(pagination.page, 10), page: parseInt(pagination.page, 10),
total: parseInt(pagination.total, 10), total: parseInt(pagination.total, 10),
}; };

View File

@@ -6,17 +6,11 @@ export const submitReceipt = ({ form }) => {
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
ApiService.post('sales/receipts', form) ApiService.post('sales/receipts', form)
.then((response) => { .then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
resolve(response); resolve(response);
}) })
.catch((error) => { .catch((error) => {
const { response } = error; const { response } = error;
const { data } = response; const { data } = response;
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
reject(data?.errors); reject(data?.errors);
}); });
}); });
@@ -60,12 +54,10 @@ export const fetchReceipt = ({ id }) => {
new Promise((resovle, reject) => { new Promise((resovle, reject) => {
ApiService.get(`sales/receipts/${id}`) ApiService.get(`sales/receipts/${id}`)
.then((response) => { .then((response) => {
const { receipt } = response.data;
dispatch({ dispatch({
type: t.RECEIPT_SET, type: t.RECEIPT_SET,
payload: { payload: { id, receipt },
id,
receipt: response.data.receipt,
},
}); });
resovle(response); resovle(response);
}) })
@@ -94,21 +86,21 @@ export const fetchReceiptsTable = ({ query = {} }) => {
dispatch({ dispatch({
type: t.RECEIPTS_PAGE_SET, type: t.RECEIPTS_PAGE_SET,
payload: { payload: {
sales_receipts: response.data.sales_receipts.results, sales_receipts: response.data.sale_receipts,
pagination: response.data.sales_receipts.pagination, pagination: response.data.pagination,
customViewId: response.data.customViewId || -1, customViewId: response.data.customViewId || -1,
}, },
}); });
dispatch({ dispatch({
type: t.RECEIPTS_ITEMS_SET, type: t.RECEIPTS_ITEMS_SET,
payload: { payload: {
sales_receipts: response.data.sales_receipts.results, sales_receipts: response.data.sale_receipts,
}, },
}); });
dispatch({ dispatch({
type: t.RECEIPTS_PAGINATION_SET, type: t.RECEIPTS_PAGINATION_SET,
payload: { payload: {
pagination: response.data.sales_receipts.pagination, pagination: response.data.pagination,
customViewId: response.data.customViewId || -1, customViewId: response.data.customViewId || -1,
}, },
}); });

View File

@@ -60,7 +60,6 @@ const reducer = createReducer(initialState, {
const viewId = customViewId || -1; const viewId = customViewId || -1;
const view = state.views[viewId] || {}; const view = state.views[viewId] || {};
state.views[viewId] = { state.views[viewId] = {
...view, ...view,
pages: { pages: {
@@ -76,7 +75,7 @@ const reducer = createReducer(initialState, {
const { pagination, customViewId } = action.payload; const { pagination, customViewId } = action.payload;
const mapped = { const mapped = {
pageSize: parseInt(pagination.pageSize, 10), pageSize: parseInt(pagination.page_size, 10),
page: parseInt(pagination.page, 10), page: parseInt(pagination.page, 10),
total: parseInt(pagination.total, 10), total: parseInt(pagination.total, 10),
}; };
@@ -85,7 +84,6 @@ const reducer = createReducer(initialState, {
pagesCount: Math.ceil(mapped.total / mapped.pageSize), pagesCount: Math.ceil(mapped.total / mapped.pageSize),
pageIndex: Math.max(mapped.page - 1, 0), pageIndex: Math.max(mapped.page - 1, 0),
}; };
state.views = { state.views = {
...state.views, ...state.views,
[customViewId]: { [customViewId]: {

View File

@@ -83,4 +83,24 @@ export default {
type: "string", type: "string",
}, },
], ],
sales_receipts: [
{
key: "next_number",
type: "number",
},
{
key: "number_prefix",
type: "string",
},
],
sales_invoices: [
{
key: "next_number",
type: "number",
},
{
key: "number_prefix",
type: "string",
},
],
}; };