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

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

View File

@@ -0,0 +1,33 @@
import React from 'react';
import styled from 'styled-components';
import { FFormGroup, FEditableText, FormattedMessage as T } from 'components';
export function ExpenseFormFooterLeft() {
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 { useExpensesTotals } from './utils';
export function ExpenseFormFooterRight() {
const { formattedSubtotal, formattedTotal } = useExpensesTotals();
return (
<ExpensesTotalLines>
<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}
/>
</ExpensesTotalLines>
);
}
const ExpensesTotalLines = styled(TotalLines)`
width: 100%;
color: #555555;
`;

View File

@@ -23,10 +23,9 @@ import {
CustomerSelectField,
AccountsSelectList,
FieldRequiredHint,
ExchangeRateInputGroup,
Hint,
If,
} from 'components';
import { ExpensesExchangeRateInputField } from './components';
import { ACCOUNT_PARENT_TYPE } from 'common/accountTypes';
import { useExpenseFormContext } from './ExpenseFormPageProvider';
@@ -34,15 +33,7 @@ import { useExpenseFormContext } from './ExpenseFormPageProvider';
* Expense form header.
*/
export default function ExpenseFormHeader() {
const {
currencies,
accounts,
customers,
isForeignCustomer,
baseCurrency,
selectCustomer,
setSelectCustomer,
} = useExpenseFormContext();
const { currencies, accounts, customers } = useExpenseFormContext();
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
@@ -118,7 +109,6 @@ export default function ExpenseFormHeader() {
selectedCurrencyCode={value}
onCurrencySelected={(currencyItem) => {
form.setFieldValue('currency_code', currencyItem.currency_code);
setSelectCustomer(currencyItem);
}}
defaultSelectText={value}
/>
@@ -126,14 +116,11 @@ export default function ExpenseFormHeader() {
)}
</FastField>
<If condition={isForeignCustomer}>
<ExchangeRateInputGroup
fromCurrency={baseCurrency}
toCurrency={selectCustomer?.currency_code}
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
</If>
{/* ----------- Exchange rate ----------- */}
<ExpensesExchangeRateInputField
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
<FastField name={'reference_no'}>
{({ form, field, meta: { error, touched } }) => (

View File

@@ -9,7 +9,10 @@ import {
AccountsListFieldCell,
CheckBoxFieldCell,
} from 'components/DataTableCells';
import { formattedAmount, safeSumBy } from 'utils';
import { useFormikContext } from 'formik';
import { ExchangeRateInputGroup } from 'components';
import { useCurrentOrganization } from 'hooks/state';
import { useExpensesIsForeign } from './utils';
/**
* Expense category header cell.
@@ -128,3 +131,27 @@ export function useExpenseFormTableColumns({ landedCost }) {
[],
);
}
;
/**
* Expense exchange rate input field.
* @returns {JSX.Element}
*/
export function ExpensesExchangeRateInputField({ ...props }) {
const currentOrganization = useCurrentOrganization();
const { values } = useFormikContext();
const isForeignJouranl = useExpensesIsForeign();
// 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

@@ -5,7 +5,7 @@ import { useFormikContext } from 'formik';
import moment from 'moment';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { first } from 'lodash';
import { first, sumBy } from 'lodash';
import { useExpenseFormContext } from './ExpenseFormPageProvider';
import {
@@ -14,7 +14,9 @@ import {
repeatValue,
ensureEntriesHasEmptyLine,
orderingLinesIndexes,
formattedAmount,
} from 'utils';
import { useCurrentOrganization } from 'hooks/state';
const ERROR = {
EXPENSE_ALREADY_PUBLISHED: 'EXPENSE.ALREADY.PUBLISHED',
@@ -150,3 +152,45 @@ export const useSetPrimaryBranchToForm = () => {
}
}, [isBranchesSuccess, setFieldValue, branches]);
};
/**
* Retreives the Journal totals.
*/
export const useExpensesTotals = () => {
const {
values: { categories, currency_code: currencyCode },
} = useFormikContext();
const total = sumBy(categories, 'amount');
// 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 useExpensesIsForeign = () => {
const { values } = useFormikContext();
const currentOrganization = useCurrentOrganization();
const isForeignExpenses = React.useMemo(
() => values.currency_code !== currentOrganization.base_currency,
[values.currency_code, currentOrganization.base_currency],
);
return isForeignExpenses;
};