feat(Sales & Purchases ): add branch & warehouse.

This commit is contained in:
elforjani13
2022-02-20 13:54:31 +02:00
parent 3ed2393cf1
commit b46c3f4843
35 changed files with 1184 additions and 28 deletions

View File

@@ -19,6 +19,7 @@ import ReceiptItemsEntriesEditor from './ReceiptItemsEntriesEditor';
import ReceiptFormFloatingActions from './ReceiptFormFloatingActions';
import ReceiptFormFooter from './ReceiptFormFooter';
import ReceiptFormDialogs from './ReceiptFormDialogs';
import ReceiptFormTopbar from './ReceiptFormTopbar';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings';
@@ -157,6 +158,7 @@ function ReceiptForm({
onSubmit={handleFormSubmit}
>
<Form>
<ReceiptFormTopbar />
<ReceiptFromHeader />
<ReceiptItemsEntriesEditor />
<ReceiptFormFooter />

View File

@@ -4,12 +4,8 @@ import { DATATYPES_LENGTH } from 'common/dataTypes';
import { isBlank } from 'utils';
const Schema = Yup.object().shape({
customer_id: Yup.string()
.label(intl.get('customer_name_'))
.required(),
receipt_date: Yup.date()
.required()
.label(intl.get('receipt_date_')),
customer_id: Yup.string().label(intl.get('customer_name_')).required(),
receipt_date: Yup.date().required().label(intl.get('receipt_date_')),
receipt_number: Yup.string()
.nullable()
.max(DATATYPES_LENGTH.STRING)
@@ -29,6 +25,8 @@ const Schema = Yup.object().shape({
.max(DATATYPES_LENGTH.TEXT)
.label(intl.get('note')),
closed: Yup.boolean(),
branch_id: Yup.string(),
warehouse_id: Yup.string(),
entries: Yup.array().of(
Yup.object().shape({
quantity: Yup.number()

View File

@@ -5,6 +5,8 @@ import {
useAccounts,
useSettingsReceipts,
useCustomers,
useWarehouses,
useBranches,
useItems,
useCreateReceipt,
useEditReceipt,
@@ -17,12 +19,9 @@ const ReceiptFormContext = createContext();
*/
function ReceiptFormProvider({ receiptId, ...props }) {
// Fetch sale receipt details.
const { data: receipt, isLoading: isReceiptLoading } = useReceipt(
receiptId,
{
enabled: !!receiptId,
},
);
const { data: receipt, isLoading: isReceiptLoading } = useReceipt(receiptId, {
enabled: !!receiptId,
});
// Fetch accounts list.
const { data: accounts, isLoading: isAccountsLoading } = useAccounts();
@@ -32,12 +31,38 @@ function ReceiptFormProvider({ receiptId, ...props }) {
isLoading: isCustomersLoading,
} = useCustomers({ page_size: 10000 });
// Fetch warehouses list.
const {
data: warehouses,
isLoading: isWarehouesLoading,
isSuccess: isWarehousesSuccess,
} = useWarehouses();
// Fetches the branches list.
const {
data: branches,
isLoading: isBranchesLoading,
isSuccess: isBranchesSuccess,
} = useBranches();
// 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' },
{
index: 1,
fieldKey: 'sellable',
value: true,
condition: '&&',
comparator: 'equals',
},
{
index: 2,
fieldKey: 'active',
value: true,
condition: '&&',
comparator: 'equals',
},
]),
[],
);
@@ -61,12 +86,16 @@ function ReceiptFormProvider({ receiptId, ...props }) {
const isNewMode = !receiptId;
const isFeatureLoading = isWarehouesLoading || isBranchesLoading;
const provider = {
receiptId,
receipt,
accounts,
customers,
items,
branches,
warehouses,
submitPayload,
isNewMode,
@@ -74,7 +103,12 @@ function ReceiptFormProvider({ receiptId, ...props }) {
isAccountsLoading,
isCustomersLoading,
isItemsLoading,
isWarehouesLoading,
isBranchesLoading,
isFeatureLoading,
isSettingLoading,
isBranchesSuccess,
isWarehousesSuccess,
createReceiptMutate,
editReceiptMutate,

View File

@@ -0,0 +1,127 @@
import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import {
Alignment,
Navbar,
NavbarGroup,
NavbarDivider,
Button,
Classes,
} from '@blueprintjs/core';
import {
useSetPrimaryWarehouseToForm,
useSetPrimaryBranchToForm,
} from './utils';
import { useFeatureCan } from 'hooks/state';
import { Icon, BranchSelect, FeatureCan, WarehouseSelect } from 'components';
import { useReceiptFormContext } from './ReceiptFormProvider';
import { Features } from 'common';
/**
* Receipt form topbar .
* @returns {JSX.Element}
*/
export default function ReceiptFormTopbar() {
// Features guard.
const { featureCan } = useFeatureCan();
// Sets the primary warehouse to form.
useSetPrimaryWarehouseToForm();
// Sets the primary branch to form.
useSetPrimaryBranchToForm();
// Can't display the navigation bar if warehouses or branches feature is not enabled.
if (!featureCan(Features.Warehouses) || !featureCan(Features.Branches)) {
return null;
}
return (
<Navbar className={'navbar--dashboard-topbar'}>
<NavbarGroup align={Alignment.LEFT}>
<FeatureCan feature={Features.Branches}>
<ReceiptFormSelectBranch />
</FeatureCan>
{featureCan(Features.Warehouses) && featureCan(Features.Branches) && (
<NavbarDivider />
)}
<FeatureCan feature={Features.Warehouses}>
<ReceiptFormSelectWarehouse />
</FeatureCan>
</NavbarGroup>
</Navbar>
);
}
/**
* Receipt select branch.
* @returns
*/
function ReceiptFormSelectBranch() {
// Receipt form context.
const { branches, isBranchesLoading } = useReceiptFormContext();
return isBranchesLoading ? (
<DetailsBarSkeletonBase className={Classes.SKELETON} />
) : (
<BranchSelect
name={'branch_id'}
branches={branches}
input={ReceiptBranchSelectButton}
popoverProps={{ minimal: true }}
/>
);
}
/**
* Receipt select warehouse.
* @returns
*/
function ReceiptFormSelectWarehouse() {
// Receipt form context.
const { warehouses, isWarehouesLoading } = useReceiptFormContext();
return isWarehouesLoading ? (
<DetailsBarSkeletonBase className={Classes.SKELETON} />
) : (
<WarehouseSelect
name={'warehouse_id'}
warehouses={warehouses}
input={ReceiptWarehouseSelectButton}
popoverProps={{ minimal: true }}
/>
);
}
function ReceiptBranchSelectButton({ label }) {
return (
<Button
text={intl.get('invoice.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/>
);
}
function ReceiptWarehouseSelectButton({ label }) {
return (
<Button
text={intl.get('invoice.warehouse_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
const DetailsBarSkeletonBase = styled.div`
letter-spacing: 10px;
margin-right: 10px;
margin-left: 10px;
font-size: 8px;
width: 140px;
height: 10px;
`;

View File

@@ -3,13 +3,14 @@ import { useFormikContext } from 'formik';
import moment from 'moment';
import * as R from 'ramda';
import intl from 'react-intl-universal';
import { omit } from 'lodash';
import { omit, first } from 'lodash';
import {
defaultFastFieldShouldUpdate,
transactionNumber,
repeatValue,
transformToForm,
} from 'utils';
import { useReceiptFormContext } from './ReceiptFormProvider';
import {
updateItemsEntriesTotal,
ensureEntriesHaveEmptyLine,
@@ -36,6 +37,8 @@ export const defaultReceipt = {
receipt_message: '',
statement: '',
closed: '',
branch_id: '',
warehouse_id: '',
entries: [...repeatValue(defaultReceiptEntry, MIN_LINES_NUMBER)],
};
@@ -142,3 +145,34 @@ export const transformFormValuesToRequest = (values) => {
closed: false,
};
};
export const useSetPrimaryWarehouseToForm = () => {
const { setFieldValue } = useFormikContext();
const { warehouses, isWarehousesSuccess } = useReceiptFormContext();
React.useEffect(() => {
if (isWarehousesSuccess) {
const primaryWarehouse =
warehouses.find((b) => b.primary) || first(warehouses);
if (primaryWarehouse) {
setFieldValue('warehouse_id', primaryWarehouse.id);
}
}
}, [isWarehousesSuccess, setFieldValue, warehouses]);
};
export const useSetPrimaryBranchToForm = () => {
const { setFieldValue } = useFormikContext();
const { branches, isBranchesSuccess } = useReceiptFormContext();
React.useEffect(() => {
if (isBranchesSuccess) {
const primaryBranch = branches.find((b) => b.primary) || first(branches);
if (primaryBranch) {
setFieldValue('branch_id', primaryBranch.id);
}
}
}, [isBranchesSuccess, setFieldValue, branches]);
};