From 119d0b2839bf6d33a99fd0b17e80c68ff6012adf Mon Sep 17 00:00:00 2001
From: elforjani13 <39470382+elforjani13@users.noreply.github.com>
Date: Mon, 29 Nov 2021 16:33:43 +0200
Subject: [PATCH] feat: Vendor Credit note.
---
src/config/sidebarMenu.js | 2 +-
.../VendorCreditNoteDeleteAlert.js | 57 ++++++++
src/containers/AlertsContainer/registered.js | 2 +
.../VendorCreditNoteFloatingActions.js | 110 ++++++++++++++++
.../CreditNoteForm/VendorCreditNoteForm.js | 111 ++++++++++++++++
.../VendorCreditNoteForm.schema.js | 44 +++++++
.../VendorCreditNoteFormFooter.js | 38 ++++++
.../VendorCreditNoteFormHeader.js | 44 +++++++
.../VendorCreditNoteFormHeaderFields.js | 124 ++++++++++++++++++
.../VendorCreditNoteFormPage.js | 21 +++
.../VendorCreditNoteFormProvider.js | 68 ++++++++++
.../VendorCreditNoteItemsEntriesEditor.js | 38 ++++++
.../CreditNotes/CreditNoteForm/utils.js | 118 +++++++++++++++++
.../VendorsCreditNoteActionsBar.js | 114 ++++++++++++++++
.../VendorsCreditNoteDataTable.js | 112 ++++++++++++++++
.../VendorsCreditNoteEmptyStatus.js | 29 ++++
.../VendorsCreditNoteListProvider.js | 27 ++++
.../VendorsCreditNoteViewTabs.js | 46 +++++++
.../VendorsCreditNotesList.js | 54 ++++++++
.../CreditNotesLanding/components.js | 88 +++++++++++++
.../withVendorsCreditNotes.js | 24 ++++
.../CreditNotes/VendorCreditNotesAlerts.js | 15 +++
.../Sales/CreditNotes/CreditNotesAlerts.js | 2 +-
.../CreditNotesActionsBar.js | 2 +-
.../CreditNotesLanding/CreditNotesList.js | 12 +-
src/containers/Settings/withSettings.js | 1 +
src/routes/dashboard.js | 43 ++++++
src/store/reducers.js | 2 +
src/store/types.js | 4 +-
.../vendorsCreditNotes.actions.js | 14 ++
.../vendorsCreditNotes.reducer.js | 34 +++++
.../vendorsCreditNotes.selector.js | 24 ++++
.../vendorsCreditNotes.type.js | 5 +
src/style/pages/VendorsCreditNote/List.scss | 20 +++
.../pages/VendorsCreditNote/PageForm.scss | 49 +++++++
35 files changed, 1488 insertions(+), 10 deletions(-)
create mode 100644 src/containers/Alerts/VendorCeditNotes/VendorCreditNoteDeleteAlert.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFloatingActions.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.schema.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormPage.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteItemsEntriesEditor.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteDataTable.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteEmptyStatus.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteListProvider.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteViewTabs.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/components.js
create mode 100644 src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotes.js
create mode 100644 src/containers/Purchases/CreditNotes/VendorCreditNotesAlerts.js
create mode 100644 src/store/vendorsCreditNotes/vendorsCreditNotes.actions.js
create mode 100644 src/store/vendorsCreditNotes/vendorsCreditNotes.reducer.js
create mode 100644 src/store/vendorsCreditNotes/vendorsCreditNotes.selector.js
create mode 100644 src/store/vendorsCreditNotes/vendorsCreditNotes.type.js
create mode 100644 src/style/pages/VendorsCreditNote/List.scss
create mode 100644 src/style/pages/VendorsCreditNote/PageForm.scss
diff --git a/src/config/sidebarMenu.js b/src/config/sidebarMenu.js
index 66e5c7a7f..928d37eb0 100644
--- a/src/config/sidebarMenu.js
+++ b/src/config/sidebarMenu.js
@@ -260,7 +260,7 @@ export default [
},
{
text: ,
- href: '/credit-notes',
+ href: '/vendors-credit-notes',
},
{
text: ,
diff --git a/src/containers/Alerts/VendorCeditNotes/VendorCreditNoteDeleteAlert.js b/src/containers/Alerts/VendorCeditNotes/VendorCreditNoteDeleteAlert.js
new file mode 100644
index 000000000..25e935099
--- /dev/null
+++ b/src/containers/Alerts/VendorCeditNotes/VendorCreditNoteDeleteAlert.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';
+
+/**
+ * Vendor Credit note delete alert.
+ */
+function VendorCreditNoteDeleteAlert({
+ name,
+
+ // #withAlertStoreConnect
+ isOpen,
+ payload: { vendorCrditNoteId },
+
+ // #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,
+)(VendorCreditNoteDeleteAlert);
diff --git a/src/containers/AlertsContainer/registered.js b/src/containers/AlertsContainer/registered.js
index dd7327daf..bbab107a3 100644
--- a/src/containers/AlertsContainer/registered.js
+++ b/src/containers/AlertsContainer/registered.js
@@ -18,6 +18,7 @@ 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';
+import VendorCreditNotesAlerts from '../Purchases/CreditNotes/VendorCreditNotesAlerts';
export default [
...AccountsAlerts,
@@ -40,4 +41,5 @@ export default [
...CurrenciesAlerts,
...RolesAlerts,
...CreditNotesAlerts,
+ ...VendorCreditNotesAlerts,
];
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFloatingActions.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFloatingActions.js
new file mode 100644
index 000000000..a8f0121f4
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFloatingActions.js
@@ -0,0 +1,110 @@
+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 { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
+
+/**
+ * Purchases Credit note floating actions.
+ */
+export default function VendorCreditNoteFloatingActions() {
+ const history = useHistory();
+
+ // Formik context.
+ const { resetForm, submitForm, isSubmitting } = useFormikContext();
+
+ // Credit note form context.
+ const { setSubmitPayload } = useVendorCreditNoteFormContext();
+
+ // Handle cancel button click.
+ const handleCancelBtnClick = (event) => {
+ history.goBack();
+ };
+
+ const handleClearBtnClick = (event) => {
+ resetForm();
+ };
+
+ return (
+
+ {/* ----------- Save And Open ----------- */}
+
+ }
+ />
+
+ } />
+ } />
+
+ }
+ minimal={true}
+ interactionKind={PopoverInteractionKind.CLICK}
+ position={Position.BOTTOM_LEFT}
+ >
+ }
+ />
+
+
+ {/* ----------- Save As Draft ----------- */}
+
+ }
+ />
+
+ } />
+ } />
+
+ }
+ minimal={true}
+ interactionKind={PopoverInteractionKind.CLICK}
+ position={Position.BOTTOM_LEFT}
+ >
+ }
+ />
+
+
+ {/* ----------- Save and New ----------- */}
+
+ {/* ----------- Clear & Reset----------- */}
+
:
}
+ />
+ {/* ----------- Cancel ----------- */}
+
}
+ />
+
+ );
+}
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js
new file mode 100644
index 000000000..735efceb2
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js
@@ -0,0 +1,111 @@
+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 {
+ CreateCreditNoteFormSchema,
+ EditCreditNoteFormSchema,
+} from './VendorCreditNoteForm.schema';
+
+import VendorCreditNoteFormHeader from './VendorCreditNoteFormHeader';
+import VendorCreditNoteItemsEntriesEditor from './VendorCreditNoteItemsEntriesEditor';
+import VendorCreditNoteFormFooter from './VendorCreditNoteFormFooter';
+import VendorCreditNoteFloatingActions from './VendorCreditNoteFloatingActions';
+import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
+
+import { AppToaster } from 'components';
+
+import { compose, safeSumBy } from 'utils';
+import {
+ defaultVendorsCreditNote,
+ filterNonZeroEntries,
+ transformToEditForm,
+ transformFormValuesToRequest,
+} from './utils';
+import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
+
+/**
+ * Vendor Credit note form.
+ */
+function VendorCreditNoteForm({
+ // #withCurrentOrganization
+ organization: { base_currency },
+}) {
+ const history = useHistory();
+ // Vendor Credit note form context.
+ const { bill } = useVendorCreditNoteFormContext();
+
+ // Initial values.
+ const initialValues = React.useMemo(
+ () => ({
+ ...(!isEmpty(bill)
+ ? {
+ ...transformToEditForm(bill),
+ currency_code: base_currency,
+ }
+ : {
+ ...defaultVendorsCreditNote,
+ currency_code: base_currency,
+ }),
+ }),
+ [],
+ );
+
+ // Handle form submit.
+ const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => {
+ const entries = filterNonZeroEntries(values.entries);
+ const totalQuantity = safeSumBy(entries, 'quantity');
+
+ if (totalQuantity === 0) {
+ AppToaster.show({
+ message: intl.get('quantity_cannot_be_zero_or_empty'),
+ intent: Intent.DANGER,
+ });
+ setSubmitting(false);
+ return;
+ }
+
+ const form = {};
+
+ // Handle the request success.
+ const onSuccess = (response) => {};
+
+ // Handle the request error.
+ const onError = ({
+ response: {
+ data: { errors },
+ },
+ }) => {};
+ };
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default compose(withCurrentOrganization())(VendorCreditNoteForm);
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.schema.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.schema.js
new file mode 100644
index 000000000..29773cb98
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.schema.js
@@ -0,0 +1,44 @@
+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({
+ vendor_id: Yup.number().required().label(intl.get('vendor_name_')),
+ bill_date: Yup.date().required().label(intl.get('bill_date_')),
+ due_date: Yup.date().required().label(intl.get('due_date_')),
+ bill_number: Yup.string()
+ .max(DATATYPES_LENGTH.STRING)
+ .label(intl.get('bill_number_')),
+ reference_no: Yup.string().nullable().min(1).max(DATATYPES_LENGTH.STRING),
+ note: Yup.string()
+ .trim()
+ .min(1)
+ .max(DATATYPES_LENGTH.TEXT)
+ .label(intl.get('note')),
+ open: Yup.boolean(),
+ 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(),
+ }),
+ total: Yup.number().nullable(),
+ discount: Yup.number().nullable().min(0).max(DATATYPES_LENGTH.INT_10),
+ description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT),
+ }),
+ ),
+});
+
+export const CreateCreditNoteFormSchema = getSchema;
+export const EditCreditNoteFormSchema = getSchema;
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.js
new file mode 100644
index 000000000..ea4ee2d99
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.js
@@ -0,0 +1,38 @@
+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';
+
+/**
+ * Vendor Credit note form footer.
+ */
+export default function VendorCreditNoteFormFooter() {
+ return (
+
+ );
+}
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.js
new file mode 100644
index 000000000..e8a552268
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import { useFormikContext } from 'formik';
+import intl from 'react-intl-universal';
+import classNames from 'classnames';
+import { CLASSES } from 'common/classes';
+import VendorCreditNoteFormHeaderFields from './VendorCreditNoteFormHeaderFields';
+
+import { getEntriesTotal } from 'containers/Entries/utils';
+import { PageFormBigNumber } from 'components';
+
+import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
+
+import { compose } from 'utils';
+
+/**
+ * Vendor Credit note header.
+ */
+function VendorCreditNoteFormHeader({
+ // #withCurrentOrganization
+ organization: { base_currency },
+}) {
+ const { values } = useFormikContext();
+
+ // Calculate the total amount.
+ const totalAmount = React.useMemo(
+ () => getEntriesTotal(values.entries),
+ [values.entries],
+ );
+
+ return (
+
+ );
+}
+
+export default compose(withCurrentOrganization())(
+ VendorCreditNoteFormHeader,
+);
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.js
new file mode 100644
index 000000000..25fd59b9c
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.js
@@ -0,0 +1,124 @@
+import React from 'react';
+import { FormGroup, InputGroup, Position } from '@blueprintjs/core';
+import { DateInput } from '@blueprintjs/datetime';
+import { FastField, Field, ErrorMessage } from 'formik';
+import { CLASSES } from 'common/classes';
+import classNames from 'classnames';
+import {
+ ContactSelecetList,
+ FieldRequiredHint,
+ Icon,
+ FormattedMessage as T,
+} from 'components';
+import { vendorsFieldShouldUpdate } from './utils';
+
+import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
+
+import {
+ momentFormatter,
+ compose,
+ tansformDateValue,
+ inputIntent,
+ handleDateChange,
+} from 'utils';
+
+/**
+ * Vendor Credit note form header fields.
+ */
+
+function VendorCreditNoteFormHeaderFields() {
+ // Credit note form context.
+ const { vendors } = useVendorCreditNoteFormContext();
+ return (
+
+ {/* ----------- Vendor name ----------- */}
+
+ {({ form, field: { value }, meta: { error, touched } }) => (
+ }
+ inline={true}
+ className={classNames(
+ 'form-group--vendor-name',
+ 'form-group--select-list',
+ CLASSES.FILL,
+ )}
+ labelInfo={}
+ intent={inputIntent({ error, touched })}
+ helperText={}
+ >
+ }
+ onContactSelected={(vendor) => {
+ form.setFieldValue('vendor_id', vendor.id);
+ }}
+ popoverFill={true}
+ />
+
+ )}
+
+
+ {/* ------- Credit note date ------- */}
+
+ {({ form, field: { value }, meta: { error, touched } }) => (
+ }
+ inline={true}
+ labelInfo={}
+ className={classNames('form-group--credit_note_date', CLASSES.FILL)}
+ intent={inputIntent({ error, touched })}
+ helperText={}
+ >
+ {
+ form.setFieldValue('bill_date', formattedDate);
+ })}
+ popoverProps={{ position: Position.BOTTOM_LEFT, minimal: true }}
+ inputProps={{
+ leftIcon: ,
+ }}
+ />
+
+ )}
+
+
+ {/* ----------- Credit note # ----------- */}
+
+ {({ field, meta: { error, touched } }) => (
+ }
+ inline={true}
+ className={('form-group--bill_number', CLASSES.FILL)}
+ intent={inputIntent({ error, touched })}
+ helperText={}
+ >
+
+
+ )}
+
+ {/* ----------- Reference ----------- */}
+
+ {({ field, meta: { error, touched } }) => (
+ }
+ inline={true}
+ className={classNames('form-group--reference', CLASSES.FILL)}
+ intent={inputIntent({ error, touched })}
+ helperText={}
+ >
+
+
+ )}
+
+
+ );
+}
+
+export default VendorCreditNoteFormHeaderFields;
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormPage.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormPage.js
new file mode 100644
index 000000000..62c966293
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormPage.js
@@ -0,0 +1,21 @@
+import React from 'react';
+import { useParams } from 'react-router-dom';
+
+import '../../../../style/pages/VendorsCreditNote/PageForm.scss';
+
+import VendorCreditNoteForm from './VendorCreditNoteForm';
+import { VendorCreditNoteFormProvider } from './VendorCreditNoteFormProvider';
+
+/**
+ * Vendor Credit note form pages.
+ */
+export default function VendorCreditNoteFormPage() {
+ const { id } = useParams();
+ const idAsInteger = parseInt(id, 10);
+
+ return (
+
+
+
+ );
+}
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js
new file mode 100644
index 000000000..0cb45a195
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js
@@ -0,0 +1,68 @@
+import React from 'react';
+import { useLocation } from 'react-router-dom';
+import { isEmpty, pick } from 'lodash';
+import DashboardInsider from 'components/Dashboard/DashboardInsider';
+import { transformToEditForm } from './utils';
+
+import { useBill, useItems, useVendors } from 'hooks/query';
+
+const VendorCreditNoteFormContext = React.createContext();
+
+/**
+ * Vendor Credit note data provider.
+ */
+function VendorCreditNoteFormProvider({ creditNoteId, ...props }) {
+ const { state } = useLocation();
+ const billId = state?.action;
+
+ // Fetches the bill by the given id.
+ const { data: bill, isLoading: isBillLoading } = useBill(billId, {
+ enabled: !!billId,
+ });
+
+ // Handle fetching the items table based on the given query.
+ const {
+ data: { items },
+ isLoading: isItemsLoading,
+ } = useItems({
+ page_size: 10000,
+ });
+
+ // Handle fetch vendors data table or list
+ const {
+ data: { vendors },
+ isLoading: isVendorsLoading,
+ } = useVendors({ page_size: 10000 });
+
+ // Form submit payload.
+ const [submitPayload, setSubmitPayload] = React.useState();
+
+ // Determines whether the form in new mode.
+ const isNewMode = !creditNoteId;
+
+ // Provider payload.
+ const provider = {
+ bill,
+ items,
+ vendors,
+ billId,
+ submitPayload,
+
+ setSubmitPayload,
+ isNewMode,
+ };
+
+ return (
+
+
+
+ );
+}
+
+const useVendorCreditNoteFormContext = () =>
+ React.useContext(VendorCreditNoteFormContext);
+
+export { VendorCreditNoteFormProvider , useVendorCreditNoteFormContext };
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteItemsEntriesEditor.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteItemsEntriesEditor.js
new file mode 100644
index 000000000..d86eb1f17
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteItemsEntriesEditor.js
@@ -0,0 +1,38 @@
+import React from 'react';
+import classNames from 'classnames';
+import { FastField } from 'formik';
+import { CLASSES } from 'common/classes';
+import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider';
+import ItemsEntriesTable from 'containers/Entries/ItemsEntriesTable';
+import { entriesFieldShouldUpdate } from './utils';
+import { ITEM_TYPE } from 'containers/Entries/utils';
+
+export default function VendorCreditNoteItemsEntriesEditor() {
+ const { items } = useVendorCreditNoteFormContext();
+ return (
+
+
+ {({
+ form: { values, setFieldValue },
+ field: { value },
+ meta: { error, touched },
+ }) => (
+ {
+ setFieldValue('entries', entries);
+ }}
+ items={items}
+ errors={error}
+ linesNumber={4}
+ currencyCode={values.currency_code}
+ />
+ )}
+
+
+ );
+}
diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js
new file mode 100644
index 000000000..c5d611c0b
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js
@@ -0,0 +1,118 @@
+import React from 'react';
+import * as R from 'ramda';
+import moment from 'moment';
+import intl from 'react-intl-universal';
+import { Intent } from '@blueprintjs/core';
+import { AppToaster } from 'components';
+import {
+ defaultFastFieldShouldUpdate,
+ transformToForm,
+ repeatValue,
+ orderingLinesIndexes,
+} from 'utils';
+import {
+ updateItemsEntriesTotal,
+ ensureEntriesHaveEmptyLine,
+} from 'containers/Entries/utils';
+import { isLandedCostDisabled } from '../../../Entries/utils';
+
+export const MIN_LINES_NUMBER = 4;
+
+// Default Vendors Credit Note entry.
+export const defaultCreditNoteEntry = {
+ index: 0,
+ item_id: '',
+ rate: '',
+ discount: '',
+ quantity: '',
+ description: '',
+ amount: '',
+};
+
+// Default Vendors Credit Note.
+export const defaultVendorsCreditNote = {
+ vendor_id: '',
+ bill_number: '',
+ bill_date: moment(new Date()).format('YYYY-MM-DD'),
+ reference_no: '',
+ note: '',
+ open: '',
+ entries: [...repeatValue(defaultCreditNoteEntry, MIN_LINES_NUMBER)],
+};
+
+/**
+ * Transformes the credit note to initial values of edit form.
+ */
+export const transformToEditForm = (creditNote) => {
+ const initialEntries = [
+ ...creditNote.entries.map((entry) => ({
+ ...transformToForm(entry, defaultCreditNoteEntry),
+ })),
+ ...repeatValue(
+ defaultCreditNoteEntry,
+ Math.max(MIN_LINES_NUMBER - creditNote.entries.length, 0),
+ ),
+ ];
+ const entries = R.compose(
+ ensureEntriesHaveEmptyLine(defaultCreditNoteEntry),
+ updateItemsEntriesTotal,
+ )(initialEntries);
+
+ return {
+ ...transformToForm(creditNote, defaultVendorsCreditNote),
+ entries,
+ };
+};
+
+
+/**
+ * Transformes credit note entries to submit request.
+ */
+ export const transformEntriesToSubmit = (entries) => {
+ const transformCreditNoteEntry = R.compose(
+ R.omit(['amount']),
+ R.curry(transformToForm)(R.__, defaultCreditNoteEntry),
+ );
+ return R.compose(orderingLinesIndexes, R.map(transformCreditNoteEntry))(entries);
+};
+
+/**
+ * Filters the givne non-zero entries.
+ */
+export const filterNonZeroEntries = (entries) => {
+ return entries.filter((item) => item.item_id && item.quantity);
+};
+
+/**
+ * Transformes form values to request body.
+ */
+ export const transformFormValuesToRequest = (values) => {
+ const entries = filterNonZeroEntries(values.entries);
+
+ return {
+ ...values,
+ entries: transformEntriesToSubmit(entries),
+ open: false,
+ };
+};
+
+
+/**
+ * Detarmines vendors fast field should update
+ */
+ export const vendorsFieldShouldUpdate = (newProps, oldProps) => {
+ return (
+ newProps.vendors !== oldProps.vendors ||
+ defaultFastFieldShouldUpdate(newProps, oldProps)
+ );
+};
+
+/**
+ * Detarmines entries fast field should update.
+ */
+ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
+ return (
+ newProps.items !== oldProps.items ||
+ defaultFastFieldShouldUpdate(newProps, oldProps)
+ );
+};
\ No newline at end of file
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js
new file mode 100644
index 000000000..12a79c20f
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js
@@ -0,0 +1,114 @@
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import {
+ Button,
+ Classes,
+ NavbarDivider,
+ NavbarGroup,
+ Intent,
+ Alignment,
+} from '@blueprintjs/core';
+import {
+ Icon,
+ FormattedMessage as T,
+ DashboardActionViewsList,
+ AdvancedFilterPopover,
+ DashboardFilterButton,
+ DashboardRowsHeightButton,
+} from 'components';
+import DashboardActionsBar from '../../../../components/Dashboard/DashboardActionsBar';
+
+import withVendorsCreditNotes from './withVendorsCreditNotes';
+import withVendorsCreditNotesActions from './withVendorsCreditNotesActions';
+import withSettings from '../../../Settings/withSettings';
+import withSettingsActions from '../../../Settings/withSettingsActions';
+
+import { compose } from 'utils';
+
+/**
+ * Vendors Credit note table actions bar.
+ */
+function VendorsCreditNoteActionsBar({
+ // #withVendorsCreditNotes
+
+ // #withVendorsCreditNotesActions
+ setVendorsCreditNoteTableState,
+
+ // #withSettings
+ creditNoteTableSize,
+
+ // #withSettingsActions
+ addSetting,
+}) {
+ const history = useHistory();
+
+ // credit note list context.
+
+ // credit note refresh action.
+
+ // Handle view tab change.
+ const handleTabChange = (view) => {
+ setVendorsCreditNoteTableState({ viewSlug: view ? view.slug : null });
+ };
+
+ // Handle click a refresh credit note.
+ const handleRefreshBtnClick = () => {};
+
+ // Handle table row size change.
+ const handleTableRowSizeChange = (size) => {
+ addSetting('vendorsCreditNote', 'tableSize', size);
+ };
+
+ return (
+
+
+
+
+ }
+ text={}
+ />
+ }
+ text={}
+ />
+ }
+ text={}
+ />
+
+
+
+
+
+ }
+ onClick={handleRefreshBtnClick}
+ />
+
+
+ );
+}
+
+export default compose(
+ withVendorsCreditNotesActions,
+ withSettingsActions,
+ withVendorsCreditNotes(({ vendorsCreditNoteTableState }) => ({
+ creditNoteFilterRoles: vendorsCreditNoteTableState.filterRoles,
+ })),
+ withSettings(({ vendorsCreditNoteSetting }) => ({
+ creditNoteTableSize: vendorsCreditNoteSetting?.tableSize,
+ })),
+)(VendorsCreditNoteActionsBar);
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteDataTable.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteDataTable.js
new file mode 100644
index 000000000..9beed42b4
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteDataTable.js
@@ -0,0 +1,112 @@
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+
+import VendorsCreditNoteEmptyStatus from './VendorsCreditNoteEmptyStatus';
+import { DataTable, DashboardContentTable } from 'components';
+import { TABLES } from 'common/tables';
+import { useMemorizedColumnsWidths } from 'hooks';
+
+import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
+import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
+
+import withDashboardActions from 'containers/Dashboard/withDashboardActions';
+import withVendorsCreditNotesActions from './withVendorsCreditNotesActions';
+import withSettings from '../../../Settings/withSettings';
+import withAlertsActions from 'containers/Alert/withAlertActions';
+
+import { useVendorsCreditNoteTableColumns } from './components';
+import { useVendorsCreditNoteListContext } from './VendorsCreditNoteListProvider';
+
+import { compose } from 'utils';
+
+/**
+ * Vendors Credit note data table.
+ */
+function VendorsCreditNoteDataTable({
+ // #withVendorsCreditNotesActions
+ setVendorsCreditNoteTableState,
+
+ // #withAlertsActions
+ openAlert,
+
+ // #withSettings
+ creditNoteTableSize,
+}) {
+ const history = useHistory();
+
+ // Credit note list context.
+
+ // Credit note table columns.
+ const columns = useVendorsCreditNoteTableColumns();
+
+ // Local storage memorizing columns widths.
+ const [initialColumnsWidths, , handleColumnResizing] =
+ useMemorizedColumnsWidths(TABLES.CREDIT_NOTE);
+
+ // Handles fetch data once the table state change.
+ const handleDataTableFetchData = React.useCallback(
+ ({ pageSize, pageIndex, sortBy }) => {
+ setVendorsCreditNoteTableState({
+ pageSize,
+ pageIndex,
+ sortBy,
+ });
+ },
+ [setVendorsCreditNoteTableState],
+ );
+
+ // Display create note empty status instead of the table.
+ // if (isEmptyStatus) {
+ // return ;
+ // }
+
+ // Handle delete credit note.
+ const handleDeleteVendorCreditNote = ({ id }) => {
+ openAlert('vendor-credit-note-delete', { creditNoteId: id });
+ };
+
+ // Handle edit credit note.
+ const hanldeEditVendorCreditNote = (creditNote) => {
+ history.push(`/vendor-credit-notes/${creditNote.id}/edit`);
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default compose(
+ withDashboardActions,
+ withVendorsCreditNotesActions,
+ withAlertsActions,
+ withSettings(({ vendorsCreditNoteSetting }) => ({
+ creditNoteTableSize: vendorsCreditNoteSetting?.tableSize,
+ })),
+)(VendorsCreditNoteDataTable);
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteEmptyStatus.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteEmptyStatus.js
new file mode 100644
index 000000000..04f928779
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteEmptyStatus.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import { Button, Intent } from '@blueprintjs/core';
+import { useHistory } from 'react-router-dom';
+import { EmptyStatus } from 'components';
+import { FormattedMessage as T } from 'components';
+
+export default function VendorsCreditNoteEmptyStatus() {
+ return (
+ }
+ description={
+
+
+
+ }
+ action={
+ <>
+
+
+
+ >
+ }
+ />
+ );
+}
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteListProvider.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteListProvider.js
new file mode 100644
index 000000000..eb18d09ec
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteListProvider.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import { isEmpty } from 'lodash';
+
+import DashboardInsider from 'components/Dashboard/DashboardInsider';
+import { getFieldsFromResourceMeta } from 'utils';
+
+const VendorsCreditNoteListContext = React.createContext();
+/**
+ * Vendors Credit note data provider.
+ */
+function VendorsCreditNoteListProvider({ query, tableStateChanged, ...props }) {
+ // Provider payload.
+ const provider = {};
+ return (
+
+
+
+ );
+}
+
+const useVendorsCreditNoteListContext = () =>
+ React.useContext(VendorsCreditNoteListContext);
+
+export { VendorsCreditNoteListProvider, useVendorsCreditNoteListContext };
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteViewTabs.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteViewTabs.js
new file mode 100644
index 000000000..149374600
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteViewTabs.js
@@ -0,0 +1,46 @@
+import React from 'react';
+import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
+
+import { DashboardViewsTabs } from 'components';
+
+import withVendorsCreditNotes from './withVendorsCreditNotes';
+import withVendorsCreditNotesActions from './withVendorsCreditNotesActions';
+
+import { compose, transfromViewsToTabs } from 'utils';
+import { useVendorsCreditNoteListContext } from './VendorsCreditNoteListProvider';
+
+/**
+ * Vendors Credit note views tabs.
+ */
+function VendorsCreditNoteViewTabs({
+ // #withVendorsCreditNotes
+ creditNoteCurrentView,
+
+ // #withVendorsCreditNotesActions
+ setVendorsCreditNoteTableState,
+}) {
+ // Credit note list context.
+
+ // Handle click a new view tab.
+ const handleClickNewView = () => {};
+
+ // const tabs = transfromViewsToTabs(creditNoteCurrentView);
+
+ // Handle tab change.
+ const handleTabsChange = (viewSlug) => {
+ setVendorsCreditNoteTableState({ viewSlug });
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default compose(
+ withVendorsCreditNotesActions,
+ withVendorsCreditNotes(({ vendorsCreditNoteTableState }) => ({
+ creditNoteCurrentView: vendorsCreditNoteTableState.viewSlug,
+ })),
+)(VendorsCreditNoteViewTabs);
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.js
new file mode 100644
index 000000000..444d44c05
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.js
@@ -0,0 +1,54 @@
+import React from 'react';
+
+import '../../../../style/pages/VendorsCreditNote/List.scss';
+
+import { DashboardPageContent } from 'components';
+import VendorsCreditNoteActionsBar from './VendorsCreditNoteActionsBar';
+import VendorsCreditNoteViewTabs from './VendorsCreditNoteViewTabs';
+import VendorsCreditNoteDataTable from './VendorsCreditNoteDataTable';
+
+import withVendorsCreditNotes from './withVendorsCreditNotes';
+import withVendorsCreditNotesActions from './withVendorsCreditNotesActions';
+
+import { VendorsCreditNoteListProvider } from './VendorsCreditNoteListProvider';
+import { transformTableStateToQuery, compose } from 'utils';
+
+function VendorsCreditNotesList({
+ // #withVendorsCreditNotes
+ vendorsCreditNoteTableState,
+ vendorsCreditNoteTableStateChanged,
+
+ // #withVendorsCreditNotesActions
+ resetVendorsCreditNoteTableState,
+}) {
+ // Resets the credit note table state once the page unmount.
+ React.useEffect(
+ () => () => {
+ resetVendorsCreditNoteTableState();
+ },
+ [resetVendorsCreditNoteTableState],
+ );
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default compose(
+ withVendorsCreditNotesActions,
+ withVendorsCreditNotes(
+ ({ vendorsCreditNoteTableState, vendorsCreditNoteTableStateChanged }) => ({
+ vendorsCreditNoteTableState,
+ vendorsCreditNoteTableStateChanged,
+ }),
+ ),
+)(VendorsCreditNotesList);
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/components.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/components.js
new file mode 100644
index 000000000..31fcf5aab
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/components.js
@@ -0,0 +1,88 @@
+import React from 'react';
+import {
+ Intent,
+ Tag,
+ Menu,
+ MenuItem,
+ MenuDivider,
+ ProgressBar,
+} from '@blueprintjs/core';
+import intl from 'react-intl-universal';
+import clsx from 'classnames';
+
+import { CLASSES } from '../../../../common/classes';
+import {
+ FormatDateCell,
+ FormattedMessage as T,
+ AppToaster,
+ Choose,
+ If,
+ Icon,
+} from 'components';
+import { formattedAmount, safeCallback, calculateStatus } from 'utils';
+
+/**
+ * Retrieve vendors credit note table columns.
+ */
+export function useVendorsCreditNoteTableColumns() {
+ return React.useMemo(
+ () => [
+ {
+ id: 'date',
+ Header: intl.get('date'),
+ accessor: 'date',
+ Cell: FormatDateCell,
+ width: 110,
+ className: 'date',
+ clickable: true,
+ textOverview: true,
+ },
+ {
+ id: 'vendor',
+ Header: intl.get('vendor_name'),
+ accessor: 'vendor.display_name',
+ width: 180,
+ className: 'vendor_id',
+ clickable: true,
+ textOverview: true,
+ },
+ {
+ id: 'credit_note',
+ Header: intl.get('credit_note.label_credit_note_no'),
+ accessor: 'credit_note',
+ width: 100,
+ className: 'credit_note',
+ clickable: true,
+ textOverview: true,
+ },
+ {
+ id: 'amount',
+ Header: intl.get('amount'),
+ // accessor: 'formatted_amount',
+ width: 120,
+ align: 'right',
+ clickable: true,
+ textOverview: true,
+ className: clsx(CLASSES.FONT_BOLD),
+ },
+ {
+ id: 'status',
+ Header: intl.get('status'),
+ // accessor:
+ width: 120, // 160
+ className: 'status',
+ clickable: true,
+ },
+ {
+ id: 'reference_no',
+ Header: intl.get('reference_no'),
+ accessor: 'reference_no',
+ width: 90,
+ className: 'reference_no',
+ clickable: true,
+ textOverview: true,
+ },
+ ],
+ [],
+ );
+}
diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotes.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotes.js
new file mode 100644
index 000000000..935983957
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/withVendorsCreditNotes.js
@@ -0,0 +1,24 @@
+import { connect } from 'react-redux';
+import {
+ getVendorsCreditNoteTableStateFactory,
+ isVendorsCreditNoteTableStateChangedFactory,
+} from '../../../../store/vendorsCreditNotes/vendorsCreditNotes.selector';
+
+export default (mapState) => {
+ const getVendorsCreditNoteTableState =
+ getVendorsCreditNoteTableStateFactory();
+ const isVendorsCreditNoteTableChanged =
+ isVendorsCreditNoteTableStateChangedFactory();
+
+ const mapStateToProps = (state, props) => {
+ const mapped = {
+ vendorsCreditNoteTableState: getVendorsCreditNoteTableState(state, props),
+ vendorsCreditNoteTableStateChanged: isVendorsCreditNoteTableChanged(
+ state,
+ props,
+ ),
+ };
+ return mapState ? mapState(mapped, state, props) : mapped;
+ };
+ return connect(mapStateToProps);
+};
diff --git a/src/containers/Purchases/CreditNotes/VendorCreditNotesAlerts.js b/src/containers/Purchases/CreditNotes/VendorCreditNotesAlerts.js
new file mode 100644
index 000000000..182c4862a
--- /dev/null
+++ b/src/containers/Purchases/CreditNotes/VendorCreditNotesAlerts.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const VendorCreditNoteDeleteAlert = React.lazy(() =>
+ import('../../Alerts/VendorCeditNotes/VendorCreditNoteDeleteAlert'),
+);
+
+/**
+ * Vendor Credit notes alerts.
+ */
+export default [
+ {
+ name: 'vendor-credit-note-delete',
+ component: VendorCreditNoteDeleteAlert,
+ },
+];
diff --git a/src/containers/Sales/CreditNotes/CreditNotesAlerts.js b/src/containers/Sales/CreditNotes/CreditNotesAlerts.js
index b0c8a57fa..58a1f4de6 100644
--- a/src/containers/Sales/CreditNotes/CreditNotesAlerts.js
+++ b/src/containers/Sales/CreditNotes/CreditNotesAlerts.js
@@ -5,7 +5,7 @@ const CreditNoteDeleteAlert = React.lazy(() =>
);
/**
- * Sales Credit notes alerts.
+ * Credit notes alerts.
*/
export default [
{
diff --git a/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js b/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js
index 13c018289..5db492fa8 100644
--- a/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js
+++ b/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js
@@ -58,7 +58,7 @@ function CreditNotesActionsBar({
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
- addSetting('salesCreditNote', 'tableSize', size);
+ addSetting('creditNote', 'tableSize', size);
};
return (
diff --git a/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.js b/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.js
index c7d8b805d..e8063ed17 100644
--- a/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.js
+++ b/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.js
@@ -22,12 +22,12 @@ function CreditNotesList({
resetCreditNotesTableState,
}) {
// Resets the credit note table state once the page unmount.
- React.useEffect(
- () => () => {
- resetCreditNotesTableState();
- },
- [resetCreditNotesTableState],
- );
+ // React.useEffect(
+ // () => () => {
+ // resetCreditNotesTableState();
+ // },
+ // [resetCreditNotesTableState],
+ // );
return (
{
cashflowTransactionsSettings: state.settings.data.cashflowTransactions,
cashflowSetting: state.settings.data.cashflow,
creditNoteSettings: state.settings.data.salesCreditNotes,
+ vendorsCreditNoteSetting:state.settings.data.vendorsCreditNotes
};
return mapState ? mapState(mapped, state, props) : mapped;
};
diff --git a/src/routes/dashboard.js b/src/routes/dashboard.js
index ef4b39d47..c55605f63 100644
--- a/src/routes/dashboard.js
+++ b/src/routes/dashboard.js
@@ -757,6 +757,49 @@ export const getDashboardRoutes = () => [
defaultSearchResource: RESOURCES_TYPES.BILL,
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
},
+ // Purchases Credit note.
+ {
+ path: `/vendors-credit-notes/:id/edit`,
+ component: lazy(() =>
+ import(
+ 'containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormPage'
+ ),
+ ),
+ name: 'vendor-credit-note-edit',
+ breadcrumb: intl.get('edit'),
+ pageTitle: intl.get('credit_note.edit_credit_note'),
+ backLink: true,
+ sidebarExpand: false,
+ defaultSearchResource: RESOURCES_TYPES.VENDOR_CREDIT_NOTE,
+ subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
+ },
+ {
+ path: '/vendors-credit-notes/new',
+ component: lazy(() =>
+ import(
+ 'containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormPage'
+ ),
+ ),
+ name: 'vendor-credit-note-new',
+ backLink: true,
+ sidebarExpand: false,
+ breadcrumb: intl.get('credit_note.new_credit_note'),
+ pageTitle: intl.get('credit_note.new_credit_note'),
+ defaultSearchResource: RESOURCES_TYPES.VENDOR_CREDIT_NOTE,
+ subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
+ },
+ {
+ path: '/vendors-credit-notes',
+ component: lazy(() =>
+ import(
+ '../containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList'
+ ),
+ ),
+ breadcrumb: intl.get('credit_note.label_list'),
+ pageTitle: intl.get('credit_note.label_list'),
+ defaultSearchResource: RESOURCES_TYPES.VENDOR_CREDIT_NOTE,
+ subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
+ },
// Subscription billing.
{
diff --git a/src/store/reducers.js b/src/store/reducers.js
index 6986efb80..d31620314 100644
--- a/src/store/reducers.js
+++ b/src/store/reducers.js
@@ -32,6 +32,7 @@ import organizations from './organizations/organizations.reducers';
import subscriptions from './subscription/subscription.reducer';
import inventoryAdjustments from './inventoryAdjustments/inventoryAdjustment.reducer';
import creditNotes from './CreditNotes/creditNotes.reducer'
+import vendorsCreditNotes from './vendorsCreditNotes/vendorsCreditNotes.reducer'
import plans from './plans/plans.reducer';
const appReducer = combineReducers({
@@ -65,6 +66,7 @@ const appReducer = combineReducers({
paymentMades,
inventoryAdjustments,
creditNotes,
+ vendorsCreditNotes,
plans
});
diff --git a/src/store/types.js b/src/store/types.js
index 44df2a872..5617f8f59 100644
--- a/src/store/types.js
+++ b/src/store/types.js
@@ -28,7 +28,8 @@ import paymentMades from './PaymentMades/paymentMades.type';
import organizations from './organizations/organizations.types';
import subscription from './subscription/subscription.types';
import inventoryAdjustments from './inventoryAdjustments/inventoryAdjustment.type';
-import creditNotes from './CreditNotes/creditNotes.type'
+import creditNotes from './CreditNotes/creditNotes.type';
+import vendorsCreditNotes from './vendorsCreditNotes/vendorsCreditNotes.type';
import plans from './plans/plans.types';
export default {
@@ -63,5 +64,6 @@ export default {
...subscription,
...inventoryAdjustments,
...creditNotes,
+ ...vendorsCreditNotes,
...plans,
};
diff --git a/src/store/vendorsCreditNotes/vendorsCreditNotes.actions.js b/src/store/vendorsCreditNotes/vendorsCreditNotes.actions.js
new file mode 100644
index 000000000..6c05d9fbd
--- /dev/null
+++ b/src/store/vendorsCreditNotes/vendorsCreditNotes.actions.js
@@ -0,0 +1,14 @@
+import t from 'store/types';
+
+export const setVendorsCreditNoteTableState = (queries) => {
+ return {
+ type: t.VENDORS_CREDIT_NOTE_TABLE_STATE_SET,
+ payload: { queries },
+ };
+};
+
+export const resetVendorsCreditNoteTableState = () => {
+ return {
+ type: t.VENDORS_CREDIT_NOTE_TABLE_STATE_RESET,
+ };
+};
diff --git a/src/store/vendorsCreditNotes/vendorsCreditNotes.reducer.js b/src/store/vendorsCreditNotes/vendorsCreditNotes.reducer.js
new file mode 100644
index 000000000..c1709dec7
--- /dev/null
+++ b/src/store/vendorsCreditNotes/vendorsCreditNotes.reducer.js
@@ -0,0 +1,34 @@
+import { createReducer } from '@reduxjs/toolkit';
+import { persistReducer, purgeStoredState } from 'redux-persist';
+import storage from 'redux-persist/lib/storage';
+import { createTableStateReducers } from 'store/tableState.reducer';
+import t from 'store/types';
+
+export const defaultTableQuery = {
+ pageSize: 20,
+ pageIndex: 0,
+ filterRoles: [],
+ viewSlug: null,
+};
+
+const initialState = {
+ tableState: defaultTableQuery,
+};
+
+const STORAGE_KEY = 'bigcapital:vendorsCreditNotes';
+
+const CONFIG = {
+ key: STORAGE_KEY,
+ whitelist: [],
+ storage,
+};
+
+const reducerInstance = createReducer(initialState, {
+ ...createTableStateReducers('VENDORS_CREDIT_NOTES', defaultTableQuery),
+
+ [t.RESET]: () => {
+ purgeStoredState(CONFIG);
+ },
+});
+
+export default persistReducer(CONFIG, reducerInstance);
diff --git a/src/store/vendorsCreditNotes/vendorsCreditNotes.selector.js b/src/store/vendorsCreditNotes/vendorsCreditNotes.selector.js
new file mode 100644
index 000000000..dc5f242fe
--- /dev/null
+++ b/src/store/vendorsCreditNotes/vendorsCreditNotes.selector.js
@@ -0,0 +1,24 @@
+import { isEqual } from 'lodash';
+import { paginationLocationQuery } from 'store/selectors';
+import { createDeepEqualSelector } from 'utils';
+import { defaultTableQuery } from './vendorsCreditNotes.reducer';
+
+const VendorsCreditNoteTableStateSelector = (state) =>
+ state.vendorsCreditNotes.tableState;
+
+export const getVendorsCreditNoteTableStateFactory = () =>
+ createDeepEqualSelector(
+ paginationLocationQuery,
+ VendorsCreditNoteTableStateSelector,
+ (locationQuery, tableState) => {
+ return {
+ ...locationQuery,
+ ...tableState,
+ };
+ },
+ );
+
+export const isVendorsCreditNoteTableStateChangedFactory = () =>
+ createDeepEqualSelector(VendorsCreditNoteTableStateSelector, (tableState) => {
+ return !isEqual(tableState, defaultTableQuery);
+ });
diff --git a/src/store/vendorsCreditNotes/vendorsCreditNotes.type.js b/src/store/vendorsCreditNotes/vendorsCreditNotes.type.js
new file mode 100644
index 000000000..91453205b
--- /dev/null
+++ b/src/store/vendorsCreditNotes/vendorsCreditNotes.type.js
@@ -0,0 +1,5 @@
+export default {
+ VENDORS_CREDIT_NOTE_TABLE_STATE_SET: 'VENDORS_CREDIT_NOTE/TABLES_STATE_SET',
+ VENDORS_CREDIT_NOTE_TABLE_STATE_RESET:
+ 'VENDORS_CREDIT_NOTE/TABLE_STATE/RESET',
+};
diff --git a/src/style/pages/VendorsCreditNote/List.scss b/src/style/pages/VendorsCreditNote/List.scss
new file mode 100644
index 000000000..5119f3081
--- /dev/null
+++ b/src/style/pages/VendorsCreditNote/List.scss
@@ -0,0 +1,20 @@
+.dashboard__insider--vendors-credit-note-list {
+ .bigcapital-datatable {
+ .tbody {
+ .amount.td {
+ .cell-inner {
+ > span {
+ font-weight: 600;
+ }
+ }
+ }
+ }
+ .table-size--small {
+ .status.td {
+ .bp3-progress-bar {
+ height: 3px;
+ }
+ }
+ }
+ }
+}
diff --git a/src/style/pages/VendorsCreditNote/PageForm.scss b/src/style/pages/VendorsCreditNote/PageForm.scss
new file mode 100644
index 000000000..ebddd4d3a
--- /dev/null
+++ b/src/style/pages/VendorsCreditNote/PageForm.scss
@@ -0,0 +1,49 @@
+body.page-vendor-credit-note-new,
+body.page-vendor-credit-note-edit {
+ .dashboard__footer {
+ display: none;
+ }
+}
+
+.dashboard__insider--vendor-credit-note-form {
+ padding-bottom: 64px;
+}
+
+.page-form--vendor-credit-note {
+ $self: '.page-form';
+
+ #{$self}__header {
+ display: flex;
+
+ &-fields {
+ flex: 1 0 0;
+ }
+
+ .bp3-label {
+ min-width: 150px;
+ }
+ .bp3-form-content {
+ width: 100%;
+ }
+
+ .bp3-form-group {
+ &.bp3-inline {
+ max-width: 450px;
+ }
+ }
+ .col--invoice-date {
+ max-width: 435px;
+ }
+ }
+ #{$self}__footer {
+ .form-group--note {
+ max-width: 450px;
+ width: 100%;
+
+ textarea {
+ width: 100%;
+ min-height: 60px;
+ }
+ }
+ }
+}