feat: add warehouse transfer & expenses & journal.

This commit is contained in:
elforjani13
2022-03-20 20:13:49 +02:00
parent 23261e975d
commit 64d73fa7b9
15 changed files with 388 additions and 149 deletions

View File

@@ -9,7 +9,6 @@ import { FastField, ErrorMessage } from 'formik';
import { DateInput } from '@blueprintjs/datetime';
import { FormattedMessage as T } from 'components';
import classNames from 'classnames';
import { Features } from 'common';
import { CLASSES } from 'common/classes';
import {
@@ -24,14 +23,12 @@ import {
FieldHint,
FieldRequiredHint,
Icon,
If,
FeatureCan,
InputPrependButton,
CurrencySelectList,
ExchangeRateInputGroup,
} from 'components';
import withSettings from 'containers/Settings/withSettings';
import { useMakeJournalFormContext } from './MakeJournalProvider';
import { JournalExchangeRateInputField } from './components';
import withDialogActions from 'containers/Dialog/withDialogActions';
import {
currenciesFieldShouldUpdate,
@@ -52,13 +49,7 @@ function MakeJournalEntriesHeader({
journalNextNumber,
journalNumberPrefix,
}) {
const {
currencies,
isForeignJournal,
baseCurrency,
selectJournalCurrency,
setSelactJournalCurrency,
} = useMakeJournalFormContext();
const { currencies } = useMakeJournalFormContext();
// Handle journal number change.
const handleJournalNumberChange = () => {
@@ -195,45 +186,35 @@ function MakeJournalEntriesHeader({
</FastField>
{/*------------ Currency -----------*/}
<FeatureCan feature={Features.ManualJournal}>
<FastField
name={'currency_code'}
currencies={currencies}
shouldUpdate={currenciesFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'currency'} />}
className={classNames('form-group--currency', CLASSES.FILL)}
inline={true}
>
<CurrencySelectList
currenciesList={currencies}
selectedCurrencyCode={value}
onCurrencySelected={(currencyItem) => {
form.setFieldValue(
'currency_code',
currencyItem.currency_code,
);
form.setFieldValue('exchange_rate', '');
setSelactJournalCurrency(currencyItem);
}}
defaultSelectText={value}
/>
</FormGroup>
)}
</FastField>
</FeatureCan>
<FastField
name={'currency_code'}
currencies={currencies}
shouldUpdate={currenciesFieldShouldUpdate}
>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'currency'} />}
className={classNames('form-group--currency', CLASSES.FILL)}
inline={true}
>
<CurrencySelectList
currenciesList={currencies}
selectedCurrencyCode={value}
onCurrencySelected={(currencyItem) => {
form.setFieldValue('currency_code', currencyItem.currency_code);
form.setFieldValue('exchange_rate', '');
}}
defaultSelectText={value}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */}
<If condition={isForeignJournal}>
<ExchangeRateInputGroup
fromCurrency={baseCurrency}
toCurrency={selectJournalCurrency?.currency_code}
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
</If>
<JournalExchangeRateInputField
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
</div>
);
}

View File

@@ -1,44 +1,29 @@
import React from 'react';
import { FastField } from 'formik';
import classNames from 'classnames';
import styled from 'styled-components';
import { CLASSES } from 'common/classes';
import { FormGroup, TextArea } from '@blueprintjs/core';
import { FormattedMessage as T } from 'components';
import { Postbox, ErrorMessage, Row, Col } from 'components';
import Dragzone from 'components/Dragzone';
import { inputIntent } from 'utils';
import { Row, Col, Paper } from 'components';
import { MakeJournalFormFooterLeft } from './MakeJournalFormFooterLeft';
import { MakeJournalFormFooterRight } from './MakeJournalFormFooterRight';
export default function MakeJournalFormFooter() {
return (
<div className={classNames(CLASSES.PAGE_FORM_FOOTER)}>
<Postbox title={<T id={'journal_details'} />} defaultOpen={false}>
<MakeJournalFooterPaper>
<Row>
<Col md={8}>
<FastField name={'description'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="description" />}
fill={true}
>
<TextArea fill={true} {...field} />
</FormGroup>
)}
</FastField>
<MakeJournalFormFooterLeft />
</Col>
<Col md={4}>
<Dragzone
initialFiles={[]}
// onDrop={handleDropFiles}
// onDeleteFile={handleDeleteFile}
hint={<T id={'attachments_maximum'} />}
/>
<MakeJournalFormFooterRight />
</Col>
</Row>
</Postbox>
</MakeJournalFooterPaper>
</div>
);
}
const MakeJournalFooterPaper = styled(Paper)`
padding: 20px;
`;

View File

@@ -0,0 +1,34 @@
import React from 'react';
import styled from 'styled-components';
import { FFormGroup, FEditableText, FormattedMessage as T } from 'components';
export function MakeJournalFormFooterLeft() {
return (
<React.Fragment>
{/* --------- Description --------- */}
<DescriptionFormGroup
label={<T id={'description'} />}
name={'description'}
>
<FEditableText
name={'description'}
placeholder={
'Enter the description of your business to be displayed in your transaction'
}
/>
</DescriptionFormGroup>
</React.Fragment>
);
}
const DescriptionFormGroup = styled(FFormGroup)`
&.bp3-form-group {
.bp3-label {
font-size: 12px;
margin-bottom: 12px;
}
.bp3-form-content {
margin-left: 10px;
}
}
`;

View File

@@ -0,0 +1,35 @@
import React from 'react';
import styled from 'styled-components';
import {
T,
TotalLines,
TotalLine,
TotalLineBorderStyle,
TotalLineTextStyle,
} from 'components';
import { useJournalTotals } from './utils';
export function MakeJournalFormFooterRight() {
const { formattedSubtotal, formattedTotal } = useJournalTotals();
return (
<MakeJouranlTotalLines>
<TotalLine
title={<T id={'manual_journal.details.subtotal'} />}
value={formattedSubtotal}
borderStyle={TotalLineBorderStyle.None}
/>
<TotalLine
title={<T id={'manual_journal.details.total'} />}
value={formattedTotal}
// borderStyle={TotalLineBorderStyle.SingleDark}
textStyle={TotalLineTextStyle.Bold}
/>
</MakeJouranlTotalLines>
);
}
const MakeJouranlTotalLines = styled(TotalLines)`
width: 100%;
color: #555555;
`;

View File

@@ -10,6 +10,10 @@ import {
BranchesListFieldCell,
} from 'components/DataTableCells';
import { useFeatureCan } from 'hooks/state';
import { useFormikContext } from 'formik';
import { ExchangeRateInputGroup } from 'components';
import { useCurrentOrganization } from 'hooks/state';
import { useJournalIsForeign } from './utils';
import { Features } from 'common';
/**
@@ -145,3 +149,26 @@ export const useJournalTableEntriesColumns = () => {
[],
);
};
/**
* Journal exchange rate input field.
* @returns {JSX.Element}
*/
export function JournalExchangeRateInputField({ ...props }) {
const currentOrganization = useCurrentOrganization();
const { values } = useFormikContext();
const isForeignJouranl = useJournalIsForeign();
// Can't continue if the customer is not foreign.
if (!isForeignJouranl) {
return null;
}
return (
<ExchangeRateInputGroup
fromCurrency={values.currency_code}
toCurrency={currentOrganization.base_currency}
{...props}
/>
);
}

View File

@@ -10,11 +10,14 @@ import {
transformToForm,
defaultFastFieldShouldUpdate,
ensureEntriesHasEmptyLine,
formattedAmount,
safeSumBy,
} from 'utils';
import { AppToaster } from 'components';
import intl from 'react-intl-universal';
import { useFormikContext } from 'formik';
import { useMakeJournalFormContext } from './MakeJournalProvider';
import { useCurrentOrganization } from 'hooks/state';
const ERROR = {
JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS',
@@ -214,3 +217,48 @@ export const useSetPrimaryBranchToForm = () => {
}
}, [isBranchesSuccess, setFieldValue, branches]);
};
/**
* Retreives the Journal totals.
*/
export const useJournalTotals = () => {
const {
values: { entries, currency_code: currencyCode },
} = useFormikContext();
// Retrieves the invoice entries total.
const totalCredit = safeSumBy(entries, 'credit');
const totalDebit = safeSumBy(entries, 'debit');
const total = Math.max(totalCredit, totalDebit);
// Retrieves the formatted total money.
const formattedTotal = React.useMemo(
() => formattedAmount(total, currencyCode),
[total, currencyCode],
);
// Retrieves the formatted subtotal.
const formattedSubtotal = React.useMemo(
() => formattedAmount(total, currencyCode, { money: false }),
[total, currencyCode],
);
return {
formattedTotal,
formattedSubtotal,
};
};
/**
* Detarmines whether the expenses has foreign .
* @returns {boolean}
*/
export const useJournalIsForeign = () => {
const { values } = useFormikContext();
const currentOrganization = useCurrentOrganization();
const isForeignJournal = React.useMemo(
() => values.currency_code !== currentOrganization.base_currency,
[values.currency_code, currentOrganization.base_currency],
);
return isForeignJournal;
};