From 0a9798e7a731d3c006663a94f5ecce1ed41e66d9 Mon Sep 17 00:00:00 2001 From: elforjani13 <39470382+elforjani13@users.noreply.github.com> Date: Mon, 29 Nov 2021 16:14:22 +0200 Subject: [PATCH] feat: Credit note. --- src/common/classes.js | 2 + src/common/resourcesTypes.js | 2 + src/config/sidebarMenu.js | 8 ++ .../CreditNotes/CreditNoteDeleteAlert.js | 57 ++++++++ src/containers/AlertsContainer/registered.js | 2 + .../withVendorsCreditNotesActions.js | 14 ++ .../CreditNoteFloatingActions.js | 109 +++++++++++++++ .../CreditNoteForm/CreditNoteForm.js | 118 +++++++++++++++++ .../CreditNoteForm/CreditNoteForm.schema.js | 51 +++++++ .../CreditNoteForm/CreditNoteFormFooter.js | 51 +++++++ .../CreditNoteForm/CreditNoteFormHeader.js | 42 ++++++ .../CreditNoteFormHeaderFields.js | 125 ++++++++++++++++++ .../CreditNoteForm/CreditNoteFormPage.js | 21 +++ .../CreditNoteForm/CreditNoteFormProvider.js | 74 +++++++++++ .../CreditNoteItemsEntriesEditorField.js | 41 ++++++ .../Sales/CreditNotes/CreditNoteForm/utils.js | 88 ++++++++++++ .../Sales/CreditNotes/CreditNotesAlerts.js | 15 +++ .../CreditNotesActionsBar.js | 117 ++++++++++++++++ .../CreditNotesDataTable.js | 104 +++++++++++++++ .../CreditNotesEmptyStatus.js | 29 ++++ .../CreditNotesLanding/CreditNotesList.js | 51 +++++++ .../CreditNotesListProvider.js | 28 ++++ .../CreditNotesLanding/CreditNotesViewTabs.js | 46 +++++++ .../CreditNotesLanding/components.js | 122 +++++++++++++++++ .../CreditNotesLanding/withCreditNotes.js | 19 +++ .../withCreditNotesActions.js | 12 ++ src/containers/Settings/withSettings.js | 1 + src/lang/en/index.json | 15 ++- src/routes/dashboard.js | 44 ++++++ src/store/CreditNotes/creditNotes.actions.js | 14 ++ src/store/CreditNotes/creditNotes.reducer.js | 34 +++++ src/store/CreditNotes/creditNotes.selector.js | 30 +++++ src/store/CreditNotes/creditNotes.type.js | 4 + src/store/reducers.js | 2 + src/store/types.js | 4 +- src/style/pages/CreditNote/List.scss | 20 +++ src/style/pages/CreditNote/PageForm.scss | 50 +++++++ 37 files changed, 1564 insertions(+), 2 deletions(-) create mode 100644 src/containers/Alerts/CreditNotes/CreditNoteDeleteAlert.js create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotesActions.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFloatingActions.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.schema.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeader.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeaderFields.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormPage.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormProvider.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteItemsEntriesEditorField.js create mode 100644 src/containers/Sales/CreditNotes/CreditNoteForm/utils.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesAlerts.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesDataTable.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesEmptyStatus.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesListProvider.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesViewTabs.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/components.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/withCreditNotes.js create mode 100644 src/containers/Sales/CreditNotes/CreditNotesLanding/withCreditNotesActions.js create mode 100644 src/store/CreditNotes/creditNotes.actions.js create mode 100644 src/store/CreditNotes/creditNotes.reducer.js create mode 100644 src/store/CreditNotes/creditNotes.selector.js create mode 100644 src/store/CreditNotes/creditNotes.type.js create mode 100644 src/style/pages/CreditNote/List.scss create mode 100644 src/style/pages/CreditNote/PageForm.scss diff --git a/src/common/classes.js b/src/common/classes.js index e1df0b33f..6b0872396 100644 --- a/src/common/classes.js +++ b/src/common/classes.js @@ -39,6 +39,8 @@ const CLASSES = { PAGE_FORM_ITEM: 'page-form--item', PAGE_FORM_MAKE_JOURNAL: 'page-form--make-journal-entries', PAGE_FORM_EXPENSE: 'page-form--expense', + PAGE_FORM_CREDIT_NOTE:'page-form--credit-note', + PAGE_FORM_VENDOR_CREDIT_NOTE:'page-form--vendor-credit-note', FORM_GROUP_LIST_SELECT: 'form-group--select-list', diff --git a/src/common/resourcesTypes.js b/src/common/resourcesTypes.js index 12ec85401..e6de2706d 100644 --- a/src/common/resourcesTypes.js +++ b/src/common/resourcesTypes.js @@ -11,4 +11,6 @@ export const RESOURCES_TYPES = { EXPENSE: 'expense', MANUAL_JOURNAL: 'manual_journal', ACCOUNT: 'account', + CREDIT_NOTE: 'credit_note', + VENDOR_CREDIT_NOTE:'vendor_credit_note' }; diff --git a/src/config/sidebarMenu.js b/src/config/sidebarMenu.js index b303d4561..66e5c7a7f 100644 --- a/src/config/sidebarMenu.js +++ b/src/config/sidebarMenu.js @@ -158,6 +158,10 @@ export default [ ability: SaleReceiptAction.View, }, }, + { + text: , + href: '/credit-notes', + }, { text: , href: '/payment-receives', @@ -254,6 +258,10 @@ export default [ ability: BillAction.View, }, }, + { + text: , + href: '/credit-notes', + }, { text: , href: '/payment-mades', diff --git a/src/containers/Alerts/CreditNotes/CreditNoteDeleteAlert.js b/src/containers/Alerts/CreditNotes/CreditNoteDeleteAlert.js new file mode 100644 index 000000000..28d6a3bc8 --- /dev/null +++ b/src/containers/Alerts/CreditNotes/CreditNoteDeleteAlert.js @@ -0,0 +1,57 @@ +import React from 'react'; +import intl from 'react-intl-universal'; +import { FormattedMessage as T, FormattedHTMLMessage } from 'components'; +import { Intent, Alert } from '@blueprintjs/core'; +import { AppToaster } from 'components'; + +import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect'; +import withAlertActions from 'containers/Alert/withAlertActions'; +import withDrawerActions from 'containers/Drawer/withDrawerActions'; + +import { compose } from 'utils'; + +/** + * Credit note delete alert. + */ +function CreditNoteDeleteAlert({ + name, + + // #withAlertStoreConnect + isOpen, + payload: { creditNoteId }, + + // #withAlertActions + closeAlert, + + // #withDrawerActions + closeDrawer, +}) { + // handle cancel delete credit note alert. + const handleCancelDeleteAlert = () => { + closeAlert(name); + }; + const handleConfirmCreditNoteDelete = () => {}; + + return ( + } + confirmButtonText={} + icon="trash" + intent={Intent.DANGER} + isOpen={isOpen} + onCancel={handleCancelDeleteAlert} + onConfirm={handleConfirmCreditNoteDelete} + // loading={isLoading} + > +

+ +

+
+ ); +} + +export default compose( + withAlertStoreConnect(), + withAlertActions, + withDrawerActions, +)(CreditNoteDeleteAlert); diff --git a/src/containers/AlertsContainer/registered.js b/src/containers/AlertsContainer/registered.js index d0e77fcfb..dd7327daf 100644 --- a/src/containers/AlertsContainer/registered.js +++ b/src/containers/AlertsContainer/registered.js @@ -17,6 +17,7 @@ import AccountTransactionsAlerts from '../CashFlow/AccountTransactions/AccountTr import UsersAlerts from '../Preferences/Users/UsersAlerts'; import CurrenciesAlerts from '../Preferences/Currencies/CurrenciesAlerts'; import RolesAlerts from '../Preferences/Users/Roles/RolesAlerts'; +import CreditNotesAlerts from '../Sales/CreditNotes/CreditNotesAlerts'; export default [ ...AccountsAlerts, @@ -38,4 +39,5 @@ export default [ ...UsersAlerts, ...CurrenciesAlerts, ...RolesAlerts, + ...CreditNotesAlerts, ]; diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotesActions.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotesActions.js new file mode 100644 index 000000000..9f1ff19b2 --- /dev/null +++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotesActions.js @@ -0,0 +1,14 @@ +import { connect } from 'react-redux'; +import { + setVendorsCreditNoteTableState, + resetVendorsCreditNoteTableState, +} from '../../../../store/vendorsCreditNotes/vendorsCreditNotes.actions'; + +const mapDispatchToProps = (dispatch) => ({ + setVendorsCreditNoteTableState: (state) => + dispatch(setVendorsCreditNoteTableState(state)), + resetVendorsCreditNoteTableState: () => + dispatch(resetVendorsCreditNoteTableState()), +}); + +export default connect(null, mapDispatchToProps); diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFloatingActions.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFloatingActions.js new file mode 100644 index 000000000..398680493 --- /dev/null +++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFloatingActions.js @@ -0,0 +1,109 @@ +import React from 'react'; +import { useHistory } from 'react-router-dom'; +import { useFormikContext } from 'formik'; +import { + Intent, + Button, + ButtonGroup, + Popover, + PopoverInteractionKind, + Position, + Menu, + MenuItem, +} from '@blueprintjs/core'; +import { If, Icon, FormattedMessage as T } from 'components'; +import { CLASSES } from 'common/classes'; +import classNames from 'classnames'; +import { useCreditNoteFormContext } from './CreditNoteFormProvider'; + +/** + * Credit note floating actions. + */ +export default function CreditNoteFloatingActions() { + const history = useHistory(); + + // Formik context. + const { resetForm, submitForm, isSubmitting } = useFormikContext(); + + // Credit note form context. + const { setSubmitPayload } = useCreditNoteFormContext(); + + // Handle cancel button click. + const handleCancelBtnClick = (event) => { + history.goBack(); + }; + + const handleClearBtnClick = (event) => { + resetForm(); + }; + + return ( +
+ {/* ----------- Save And Deliver ----------- */} + +
+ ); +} diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js new file mode 100644 index 000000000..503ce1000 --- /dev/null +++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js @@ -0,0 +1,118 @@ +import React from 'react'; +import { useHistory } from 'react-router-dom'; +import { Formik, Form } from 'formik'; +import { Intent } from '@blueprintjs/core'; +import intl from 'react-intl-universal'; +import { sumBy, omit, isEmpty } from 'lodash'; +import classNames from 'classnames'; +import { CLASSES } from 'common/classes'; +import { + getCreateCreditNoteFormSchema, + getEditCreditNoteFormSchema, +} from './CreditNoteForm.schema'; + +import CreditNoteFormHeader from './CreditNoteFormHeader'; +import CreditNoteItemsEntriesEditorField from './CreditNoteItemsEntriesEditorField'; +import CreditNoteFormFooter from './CreditNoteFormFooter'; +import CreditNoteFloatingActions from './CreditNoteFloatingActions'; + +import { AppToaster } from 'components'; +import { compose, orderingLinesIndexes, transactionNumber } from 'utils'; +import { useCreditNoteFormContext } from './CreditNoteFormProvider'; +import { transformToEditForm, defaultCreditNote } from './utils'; + +import withSettings from 'containers/Settings/withSettings'; +import withCurrentOrganization from 'containers/Organization/withCurrentOrganization'; + +/** + * Credit note form. + */ +function CreditNoteForm({ + // #withSettings + + // #withCurrentOrganization + organization: { base_currency }, +}) { + const history = useHistory(); + + // Credit note form context. + const { invoice } = useCreditNoteFormContext(); + + // Initial values. + const initialValues = React.useMemo( + () => ({ + ...(!isEmpty(invoice) + ? { ...transformToEditForm(invoice), currency_code: base_currency } + : { + ...defaultCreditNote, + entries: orderingLinesIndexes(defaultCreditNote.entries), + currency_code: base_currency, + }), + }), + [], + ); + + // Handle form submit. + const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => { + setSubmitting(true); + + const entries = values.entries.filter( + (item) => item.item_id && item.quantity, + ); + + const totalQuantity = sumBy(entries, (entry) => parseInt(entry.quantity)); + + // Throw danger toaster in case total quantity equals zero. + if (totalQuantity === 0) { + AppToaster.show({ + message: intl.get('quantity_cannot_be_zero_or_empty'), + intent: Intent.DANGER, + }); + setSubmitting(false); + return; + } + // Transformes the values of the form to request. + const form = { + // ...transformValueToRequest(values), + }; + + // Handle the request success. + const onSuccess = () => {}; + // Handle the request error. + const onError = ({ + response: { + data: { errors }, + }, + }) => {}; + }; + + const CreateCreditNoteFormSchema = getCreateCreditNoteFormSchema(); + const EditCreditNoteFormSchema = getEditCreditNoteFormSchema(); + + return ( +
+ +
+ + + + + +
+
+ ); +} + +export default compose(withCurrentOrganization())(CreditNoteForm); diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.schema.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.schema.js new file mode 100644 index 000000000..69aa5ee38 --- /dev/null +++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.schema.js @@ -0,0 +1,51 @@ +import * as Yup from 'yup'; +import intl from 'react-intl-universal'; +import { DATATYPES_LENGTH } from 'common/dataTypes'; +import { isBlank } from 'utils'; + +const getSchema = () => Yup.object().shape({ + customer_id: Yup.string() + .label(intl.get('customer_name_')) + .required(), + invoice_date: Yup.date() + .required() + .label(intl.get('invoice_date_')), + invoice_no: Yup.string() + .max(DATATYPES_LENGTH.STRING) + .label(intl.get('invoice_no_')), + reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING), + delivered: Yup.boolean(), + invoice_message: Yup.string() + .trim() + .min(1) + .max(DATATYPES_LENGTH.TEXT) + .label(intl.get('note')), + terms_conditions: Yup.string() + .trim() + .min(1) + .max(DATATYPES_LENGTH.TEXT) + .label(intl.get('note')), + entries: Yup.array().of( + Yup.object().shape({ + quantity: Yup.number() + .nullable() + .max(DATATYPES_LENGTH.INT_10) + .when(['rate'], { + is: (rate) => rate, + then: Yup.number().required(), + }), + rate: Yup.number().nullable().max(DATATYPES_LENGTH.INT_10), + item_id: Yup.number() + .nullable() + .when(['quantity', 'rate'], { + is: (quantity, rate) => !isBlank(quantity) && !isBlank(rate), + then: Yup.number().required(), + }), + discount: Yup.number().nullable().min(0).max(100), + description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT), + }), + ), +}); + +export const getCreateCreditNoteFormSchema = getSchema; +export const getEditCreditNoteFormSchema = getSchema; \ No newline at end of file diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.js new file mode 100644 index 000000000..9f4b1af1b --- /dev/null +++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.js @@ -0,0 +1,51 @@ +import React from 'react'; +import { FastField } from 'formik'; +import { FormGroup, TextArea } from '@blueprintjs/core'; +import { FormattedMessage as T } from 'components'; +import { CLASSES } from 'common/classes'; +import { Row, Col, Postbox } from 'components'; +import { inputIntent } from 'utils'; +import classNames from 'classnames'; + +/** + * Credit note form footer. + */ +export default function CreditNoteFormFooter() { + return ( +
+ } + defaultOpen={false} + > + + + {/* --------- Customer notes --------- */} + + {({ field, meta: { error, touched } }) => ( + } + className={'form-group--customer_notes'} + intent={inputIntent({ error, touched })} + > +