diff --git a/client/src/containers/Entries/components.js b/client/src/containers/Entries/components.js
index 59db5385d..05380a388 100644
--- a/client/src/containers/Entries/components.js
+++ b/client/src/containers/Entries/components.js
@@ -75,7 +75,7 @@ export function QuantityTotalFooterCell({ rows }) {
* Total footer cell.
*/
export function TotalFooterCell({ payload: { currencyCode }, rows }) {
- const total = safeSumBy(rows, 'original.total');
+ const total = safeSumBy(rows, 'original.amount');
return {formattedAmount(total, currencyCode)};
}
@@ -168,7 +168,7 @@ export function useEditableItemsEntriesColumns({ landedCost }) {
{
Header: intl.get('total'),
Footer: TotalFooterCell,
- accessor: 'total',
+ accessor: 'amount',
Cell: TotalCell,
disableSortBy: true,
width: 100,
diff --git a/client/src/containers/Entries/utils.js b/client/src/containers/Entries/utils.js
index 6024f8db3..437f7faf2 100644
--- a/client/src/containers/Entries/utils.js
+++ b/client/src/containers/Entries/utils.js
@@ -1,3 +1,4 @@
+import { sumBy } from 'lodash';
import { toSafeNumber } from 'utils';
/**
@@ -21,7 +22,7 @@ export const calcItemEntryTotal = (discount, quantity, rate) => {
export function updateItemsEntriesTotal(rows) {
return rows.map((row) => ({
...row,
- total: calcItemEntryTotal(row.discount, row.quantity, row.rate),
+ amount: calcItemEntryTotal(row.discount, row.quantity, row.rate),
}));
}
@@ -29,3 +30,10 @@ export const ITEM_TYPE = {
SELLABLE: 'SELLABLE',
PURCHASABLE: 'PURCHASABLE',
};
+
+/**
+ * Retrieve total of the given items entries.
+ */
+export function getEntriesTotal(entries) {
+ return sumBy(entries, 'amount');
+}
\ No newline at end of file
diff --git a/client/src/containers/Purchases/Bills/BillForm/BillFormHeader.js b/client/src/containers/Purchases/Bills/BillForm/BillFormHeader.js
index 08676967b..da26f1d94 100644
--- a/client/src/containers/Purchases/Bills/BillForm/BillFormHeader.js
+++ b/client/src/containers/Purchases/Bills/BillForm/BillFormHeader.js
@@ -21,7 +21,7 @@ function BillFormHeader({
const { values } = useFormikContext();
// Calculate the total due amount of bill entries.
- const totalDueAmount = useMemo(() => sumBy(values.entries, 'total'), [
+ const totalDueAmount = useMemo(() => sumBy(values.entries, 'amount'), [
values.entries,
]);
diff --git a/client/src/containers/Purchases/Bills/BillForm/utils.js b/client/src/containers/Purchases/Bills/BillForm/utils.js
index 9723b4f97..531179c38 100644
--- a/client/src/containers/Purchases/Bills/BillForm/utils.js
+++ b/client/src/containers/Purchases/Bills/BillForm/utils.js
@@ -17,6 +17,7 @@ export const defaultBillEntry = {
discount: '',
quantity: '',
description: '',
+ amount: '',
landed_cost: false,
};
diff --git a/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js b/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js
index 1b8e540ce..758232be2 100644
--- a/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js
+++ b/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js
@@ -89,6 +89,7 @@ function EstimateForm({
);
const totalQuantity = sumBy(entries, (entry) => parseInt(entry.quantity));
+ // Validate the entries quantity should be bigger than zero.
if (totalQuantity === 0) {
AppToaster.show({
message: intl.get('quantity_cannot_be_zero_or_empty'),
diff --git a/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.js b/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.js
index 9402d5d75..38b1f2de9 100644
--- a/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.js
+++ b/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.js
@@ -1,14 +1,15 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
-import { sumBy } from 'lodash';
import { useFormikContext } from 'formik';
import intl from 'react-intl-universal';
import { CLASSES } from 'common/classes';
-
import EstimateFormHeaderFields from './EstimateFormHeaderFields';
-import { PageFormBigNumber } from 'components';
+
import withSettings from 'containers/Settings/withSettings';
+
+import { getEntriesTotal } from 'containers/Entries/utils';
+import { PageFormBigNumber } from 'components';
import { compose } from 'utils';
// Estimate form top header.
@@ -20,7 +21,7 @@ function EstimateFormHeader({
// Calculate the total due amount of bill entries.
const totalDueAmount = useMemo(
- () => sumBy(values.entries, 'total'),
+ () => getEntriesTotal(values.entries),
[values.entries],
);
diff --git a/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormProvider.js b/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormProvider.js
index 3c942de78..85f89a499 100644
--- a/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormProvider.js
+++ b/client/src/containers/Sales/Estimates/EstimateForm/EstimateFormProvider.js
@@ -8,6 +8,7 @@ import {
useCreateEstimate,
useEditEstimate,
} from 'hooks/query';
+import { ITEMS_FILTER_ROLES } from './utils';
const EstimateFormContext = createContext();
@@ -18,31 +19,24 @@ function EstimateFormProvider({ estimateId, ...props }) {
const {
data: estimate,
isFetching: isEstimateFetching,
+ isLoading: isEstimateLoading,
} = useEstimate(estimateId, { enabled: !!estimateId });
- // Filter all sellable items only.
- const stringifiedFilterRoles = React.useMemo(
- () =>
- JSON.stringify([
- { index: 1, fieldKey: 'sellable', value: true, condition: '&&', comparator: 'equals', },
- { index: 2, fieldKey: 'active', value: true, condition: '&&', comparator: 'equals' },
- ]),
- [],
- );
-
// Handle fetch Items data table or list
const {
data: { items },
isFetching: isItemsFetching,
+ isLoading: isItemsLoading,
} = useItems({
page_size: 10000,
- stringified_filter_roles: stringifiedFilterRoles,
+ stringified_filter_roles: ITEMS_FILTER_ROLES,
});
// Handle fetch customers data table or list
const {
data: { customers },
isFetch: isCustomersFetching,
+ isLoading: isCustomersLoading,
} = useCustomers({ page_size: 10000 });
// Handle fetch settings.
@@ -68,6 +62,10 @@ function EstimateFormProvider({ estimateId, ...props }) {
isItemsFetching,
isEstimateFetching,
+ isCustomersLoading,
+ isItemsLoading,
+ isEstimateLoading,
+
submitPayload,
setSubmitPayload,
@@ -77,7 +75,7 @@ function EstimateFormProvider({ estimateId, ...props }) {
return (
diff --git a/client/src/containers/Sales/Estimates/EstimateForm/utils.js b/client/src/containers/Sales/Estimates/EstimateForm/utils.js
index eba82d104..3056c29f7 100644
--- a/client/src/containers/Sales/Estimates/EstimateForm/utils.js
+++ b/client/src/containers/Sales/Estimates/EstimateForm/utils.js
@@ -17,6 +17,7 @@ export const defaultEstimateEntry = {
discount: '',
quantity: '',
description: '',
+ amount: '',
};
export const defaultEstimate = {
@@ -55,7 +56,7 @@ export const useObserveEstimateNoSettings = (prefix, nextNumber) => {
setFieldValue('estimate_number', estimateNo);
}, [setFieldValue, prefix, nextNumber]);
};
-
+
/**
* Detarmines customers fast field when update.
*/
@@ -75,3 +76,20 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
defaultFastFieldShouldUpdate(newProps, oldProps)
);
};
+
+export const ITEMS_FILTER_ROLES = JSON.stringify([
+ {
+ index: 1,
+ fieldKey: 'sellable',
+ value: true,
+ condition: '&&',
+ comparator: 'equals',
+ },
+ {
+ index: 2,
+ fieldKey: 'active',
+ value: true,
+ condition: '&&',
+ comparator: 'equals',
+ },
+]);
diff --git a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.js b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.js
index 18b958b18..0712a63ea 100644
--- a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.js
+++ b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.js
@@ -1,13 +1,14 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
-import { sumBy } from 'lodash';
import { useFormikContext } from 'formik';
import intl from 'react-intl-universal';
import { CLASSES } from 'common/classes';
import InvoiceFormHeaderFields from './InvoiceFormHeaderFields';
+import { getEntriesTotal } from 'containers/Entries/utils';
import { PageFormBigNumber } from 'components';
+
import withSettings from 'containers/Settings/withSettings';
import { compose } from 'redux';
@@ -23,7 +24,7 @@ function InvoiceFormHeader({
// Calculate the total due amount of invoice entries.
const totalDueAmount = useMemo(
- () => sumBy(values.entries, 'total'),
+ () => getEntriesTotal(values.entries),
[values.entries],
);
diff --git a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.js b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.js
index 539f09e33..d7696c146 100644
--- a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.js
+++ b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.js
@@ -2,7 +2,7 @@ import React, { createContext, useState } from 'react';
import { isEmpty, pick } from 'lodash';
import { useLocation } from 'react-router-dom';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
-import { transformToEditForm } from './utils';
+import { transformToEditForm, ITEMS_FILTER_ROLES_QUERY } from './utils';
import {
useInvoice,
useItems,
@@ -27,10 +27,10 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
});
// Fetches the estimate by the given id.
- const {
- data: estimate,
- isLoading: isEstimateLoading,
- } = useEstimate(estimateId, { enabled: !!estimateId });
+ const { data: estimate, isLoading: isEstimateLoading } = useEstimate(
+ estimateId,
+ { enabled: !!estimateId },
+ );
const newInvoice = !isEmpty(estimate)
? transformToEditForm({
@@ -38,23 +38,13 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
})
: [];
- // Filter all sellable items only.
- const stringifiedFilterRoles = React.useMemo(
- () =>
- JSON.stringify([
- { index: 1, fieldKey: 'sellable', value: true, condition: '&&', comparator: 'equals', },
- { index: 2, fieldKey: 'active', value: true, condition: '&&', comparator: 'equals' },
- ]),
- [],
- );
-
// Handle fetching the items table based on the given query.
const {
data: { items },
isLoading: isItemsLoading,
} = useItems({
page_size: 10000,
- stringified_filter_roles: stringifiedFilterRoles,
+ stringified_filter_roles: ITEMS_FILTER_ROLES_QUERY,
});
// Handle fetch customers data table or list
diff --git a/client/src/containers/Sales/Invoices/InvoiceForm/utils.js b/client/src/containers/Sales/Invoices/InvoiceForm/utils.js
index 70787c7fa..2f0ee469c 100644
--- a/client/src/containers/Sales/Invoices/InvoiceForm/utils.js
+++ b/client/src/containers/Sales/Invoices/InvoiceForm/utils.js
@@ -26,7 +26,7 @@ export const defaultInvoiceEntry = {
discount: '',
quantity: '',
description: '',
- total: 0,
+ amount: '',
};
// Default invoice object.
@@ -63,6 +63,9 @@ export function transformToEditForm(invoice) {
};
}
+/**
+ * Transformes the response errors types.
+ */
export const transformErrors = (errors, { setErrors }) => {
if (errors.some((e) => e.type === ERROR.SALE_INVOICE_NUMBER_IS_EXISTS)) {
setErrors({
@@ -102,6 +105,9 @@ export const useObserveInvoiceNoSettings = (prefix, nextNumber) => {
}, [setFieldValue, prefix, nextNumber]);
};
+/**
+ * Detarmines customer name field when should update.
+ */
export const customerNameFieldShouldUpdate = (newProps, oldProps) => {
return (
newProps.customers !== oldProps.customers ||
@@ -109,9 +115,29 @@ export const customerNameFieldShouldUpdate = (newProps, oldProps) => {
);
};
+/**
+ * Detarmines invoice entries field when should update.
+ */
export const entriesFieldShouldUpdate = (newProps, oldProps) => {
return (
newProps.items !== oldProps.items ||
defaultFastFieldShouldUpdate(newProps, oldProps)
);
};
+
+export const ITEMS_FILTER_ROLES_QUERY = JSON.stringify([
+ {
+ index: 1,
+ fieldKey: 'sellable',
+ value: true,
+ condition: '&&',
+ comparator: 'equals',
+ },
+ {
+ index: 2,
+ fieldKey: 'active',
+ value: true,
+ condition: '&&',
+ comparator: 'equals',
+ },
+]);
diff --git a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.js b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.js
index 87ee106e6..ef0ca3125 100644
--- a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.js
+++ b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.js
@@ -1,15 +1,15 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
-import { sumBy } from 'lodash';
import { useFormikContext } from 'formik';
-
-import { CLASSES } from 'common/classes';
-import ReceiptFormHeaderFields from './ReceiptFormHeaderFields';
-
-import { PageFormBigNumber } from 'components';
import intl from 'react-intl-universal';
+import { CLASSES } from 'common/classes';
+import { PageFormBigNumber } from 'components';
+import ReceiptFormHeaderFields from './ReceiptFormHeaderFields';
+
import withSettings from 'containers/Settings/withSettings';
+
+import { getEntriesTotal } from 'containers/Entries/utils';
import { compose } from 'redux';
/**
@@ -25,7 +25,7 @@ function ReceiptFormHeader({
// Calculate the total due amount of bill entries.
const totalDueAmount = useMemo(
- () => sumBy(values.entries, 'total'),
+ () => getEntriesTotal(values.entries),
[values.entries],
);
diff --git a/client/src/containers/Sales/Receipts/ReceiptForm/utils.js b/client/src/containers/Sales/Receipts/ReceiptForm/utils.js
index 93cbb75cd..d4b82d660 100644
--- a/client/src/containers/Sales/Receipts/ReceiptForm/utils.js
+++ b/client/src/containers/Sales/Receipts/ReceiptForm/utils.js
@@ -17,6 +17,7 @@ export const defaultReceiptEntry = {
discount: '',
quantity: '',
description: '',
+ amount: '',
};
export const defaultReceipt = {
diff --git a/client/src/style/App.scss b/client/src/style/App.scss
index 588e1e6c5..927ed9e04 100644
--- a/client/src/style/App.scss
+++ b/client/src/style/App.scss
@@ -26,6 +26,7 @@
@import 'components/PageForm';
@import 'components/Tooltip';
@import 'components/Postbox';
+@import 'components/SidebarOverlay';
// Pages
@import 'pages/view-form';
@@ -201,134 +202,6 @@ html[lang^="ar"] {
}
}
-
-.sidebar-overlay {
- background: #fff;
- height: 100%;
- width: 225px;
- outline: 0;
- box-shadow: 0 0 2px rgba(0, 0, 0, 0.1);
-
- &__scroll-wrapper {
- height: 100%
- }
-
- .ScrollbarsCustom-Track {
-
- &.ScrollbarsCustom-TrackY,
- &.ScrollbarsCustom-TrackX {
- background: rgba(0, 0, 0, 0);
- }
- }
-
- .ScrollbarsCustom-Thumb {
-
- &.ScrollbarsCustom-ThumbX,
- &.ScrollbarsCustom-ThumbY {
- background: rgba(0, 0, 0, 0);
- }
- }
-
- .ScrollbarsCustom-Content {
- display: flex;
- flex-direction: column;
- height: 100%;
- }
-
- &:hover {
- .ScrollbarsCustom-Thumb {
-
- &.ScrollbarsCustom-ThumbX,
- &.ScrollbarsCustom-ThumbY {
- background: rgba(0, 0, 0, 0.5);
- }
- }
- }
-
- &__menu {
- margin: 16px 0;
- }
-
- &__item {
- font-size: 15px;
- color: #00102b;
-
- a {
- color: inherit;
- display: block;
- padding: 10px 22px;
- text-decoration: none;
-
- &:hover,
- &:focus{
- background: #f3f3f3;
- }
- }
- }
-
- &__divider {
- height: 1px;
- margin: 6px 0;
- background: #e2e5ec;
- }
-
- &__label{
- text-transform: uppercase;
- font-size: 12px;
- padding: 14px 20px 10px;
- letter-spacing: 1px;
- color: #707a85;
-
- html[lang^="ar"] & {
- font-size: 13px;
- letter-spacing: 0;
- font-weight: 500;
- }
- }
-
- &__label + .sidebar-overlay__divider{
- margin-top: 0;
- }
-}
-
-.sidebar-overlay-transition {
- transform: translateX(-100%);
-
- &.bp3-overlay{
- &-appear,
- &-enter {
- transform: translateX(-100%)
- }
-
- &-appear-active,
- &-enter-active {
- transform: translateX(0) !important;
- transition: all 100ms ease-in-out;
- }
-
- &-appear-done,
- &-enter-done {
- transform: translateX(0) !important;
- }
-
- &-exit {
- transform: translateX(0) !important;
- }
- &-exit-active {
- transform: translateX(-100%) !important;
- transition: all 100ms ease-in-out;
- }
- &-exit-done{
- transform: translateX(-100%) !important;
- }
- }
-
-}
-.sidebar-overlay-backdrop{
- background-color: rgba(0, 10, 30, 0.15);
-}
-
-
.bp3-popover2{
box-shadow: 0 0 0;
}
diff --git a/client/src/style/components/SidebarOverlay.scss b/client/src/style/components/SidebarOverlay.scss
new file mode 100644
index 000000000..dc16f7876
--- /dev/null
+++ b/client/src/style/components/SidebarOverlay.scss
@@ -0,0 +1,129 @@
+
+
+.sidebar-overlay {
+ background: #fff;
+ height: 100%;
+ width: 225px;
+ outline: 0;
+ box-shadow: 0 0 2px rgba(0, 0, 0, 0.1);
+
+ &__scroll-wrapper {
+ height: 100%
+ }
+
+ .ScrollbarsCustom-Track {
+
+ &.ScrollbarsCustom-TrackY,
+ &.ScrollbarsCustom-TrackX {
+ background: rgba(0, 0, 0, 0);
+ }
+ }
+
+ .ScrollbarsCustom-Thumb {
+
+ &.ScrollbarsCustom-ThumbX,
+ &.ScrollbarsCustom-ThumbY {
+ background: rgba(0, 0, 0, 0);
+ }
+ }
+
+ .ScrollbarsCustom-Content {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ }
+
+ &:hover {
+ .ScrollbarsCustom-Thumb {
+
+ &.ScrollbarsCustom-ThumbX,
+ &.ScrollbarsCustom-ThumbY {
+ background: rgba(0, 0, 0, 0.5);
+ }
+ }
+ }
+
+ &__menu {
+ margin: 16px 0;
+ }
+
+ &__item {
+ font-size: 15px;
+ color: #00102b;
+
+ a {
+ color: inherit;
+ display: block;
+ padding: 10px 22px;
+ text-decoration: none;
+
+ &:hover,
+ &:focus{
+ background: #f3f3f3;
+ }
+ }
+ }
+
+ &__divider {
+ height: 1px;
+ margin: 6px 0;
+ background: #e2e5ec;
+ }
+
+ &__label{
+ text-transform: uppercase;
+ font-size: 12px;
+ padding: 14px 20px 10px;
+ letter-spacing: 1px;
+ color: #707a85;
+
+ html[lang^="ar"] & {
+ font-size: 13px;
+ letter-spacing: 0;
+ font-weight: 500;
+ }
+ }
+
+ &__label + .sidebar-overlay__divider{
+ margin-top: 0;
+ }
+ }
+
+ .sidebar-overlay-transition {
+ transform: translateX(-100%);
+
+ &.bp3-overlay{
+ &-appear,
+ &-enter {
+ transform: translateX(-100%)
+ }
+
+ &-appear-active,
+ &-enter-active {
+ transform: translateX(0) !important;
+ transition: all 100ms ease-in-out;
+ }
+
+ &-appear-done,
+ &-enter-done {
+ transform: translateX(0) !important;
+ }
+
+ &-exit {
+ transform: translateX(0) !important;
+ }
+ &-exit-active {
+ transform: translateX(-100%) !important;
+ transition: all 100ms ease-in-out;
+ }
+ &-exit-done{
+ transform: translateX(-100%) !important;
+ }
+ }
+
+ }
+ .sidebar-overlay-backdrop{
+ background-color: rgba(0, 10, 30, 0.15);
+ }
+
+
\ No newline at end of file