feat: wip categorize the cashflow transactions
This commit is contained in:
@@ -80,10 +80,7 @@ export default class NewCashflowTransactionController extends BaseController {
|
||||
public get categorizeCashflowTransactionValidationSchema() {
|
||||
return [
|
||||
check('date').exists().isISO8601().toDate(),
|
||||
oneOf([
|
||||
check('to_account_id').exists().isInt().toInt(),
|
||||
check('from_account_id').exists().isInt().toInt(),
|
||||
]),
|
||||
check('credit_account_id').exists().isInt().toInt(),
|
||||
check('transaction_number').optional(),
|
||||
check('transaction_type').exists(),
|
||||
check('reference_no').optional(),
|
||||
|
||||
@@ -235,8 +235,7 @@ export interface ICashflowTransactionSchema {
|
||||
export interface ICashflowTransactionInput extends ICashflowTransactionSchema {}
|
||||
|
||||
export interface ICategorizeCashflowTransactioDTO {
|
||||
fromAccountId: number;
|
||||
toAccountId: number;
|
||||
creditAccountId: number;
|
||||
referenceNo: string;
|
||||
transactionNumber: string;
|
||||
transactionType: string;
|
||||
|
||||
@@ -318,7 +318,7 @@ export default class Account extends mixin(TenantModel, [
|
||||
to: 'uncategorized_cashflow_transactions.accountId',
|
||||
},
|
||||
filter: (query) => {
|
||||
query.filter('categorized', false);
|
||||
query.where('categorized', false);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable global-require */
|
||||
import TenantModel from 'models/TenantModel';
|
||||
import { Model } from 'objection';
|
||||
import { Model, ModelOptions, QueryContext } from 'objection';
|
||||
import Account from './Account';
|
||||
|
||||
export default class UncategorizedCashflowTransaction extends TenantModel {
|
||||
@@ -95,6 +95,19 @@ export default class UncategorizedCashflowTransaction extends TenantModel {
|
||||
.increment('uncategorized_transactions', 1);
|
||||
}
|
||||
|
||||
public async $afterUpdate(
|
||||
opt: ModelOptions,
|
||||
queryContext: QueryContext
|
||||
): void | Promise<any> {
|
||||
await super.$afterUpdate(opt, queryContext);
|
||||
|
||||
if (this.id && this.categorized) {
|
||||
await Account.query(queryContext.transaction)
|
||||
.findById(this.accountId)
|
||||
.decrement('uncategorized_transactions', 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param queryContext
|
||||
@@ -102,7 +115,7 @@ export default class UncategorizedCashflowTransaction extends TenantModel {
|
||||
public async $afterDelete(queryContext) {
|
||||
await super.$afterDelete(queryContext);
|
||||
|
||||
await Account.query()
|
||||
await Account.query(queryContext.transaction)
|
||||
.findById(this.accountId)
|
||||
.decrement('uncategorized_transactions', 1);
|
||||
}
|
||||
|
||||
@@ -79,13 +79,14 @@ export class CategorizeCashflowTransaction {
|
||||
cashflowTransactionDTO
|
||||
);
|
||||
// Updates the uncategorized transaction as categorized.
|
||||
await UncategorizedCashflowTransaction.query(trx)
|
||||
.findById(uncategorizedTransactionId)
|
||||
.patch({
|
||||
await UncategorizedCashflowTransaction.query(trx).patchAndFetchById(
|
||||
uncategorizedTransactionId,
|
||||
{
|
||||
categorized: true,
|
||||
categorizeRefType: 'CashflowTransaction',
|
||||
categorizeRefId: cashflowTransaction.id,
|
||||
});
|
||||
}
|
||||
);
|
||||
// Triggers `onCashflowTransactionCategorized` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.cashflow.onTransactionCategorized,
|
||||
|
||||
@@ -31,6 +31,7 @@ export default class GetCashflowTransactionsService {
|
||||
.withGraphFetched('entries.cashflowAccount')
|
||||
.withGraphFetched('entries.creditAccount')
|
||||
.withGraphFetched('transactions.account')
|
||||
.orderBy('date', 'DESC')
|
||||
.throwIfNotFound();
|
||||
|
||||
this.throwErrorCashflowTranscationNotFound(cashflowTransaction);
|
||||
|
||||
@@ -24,7 +24,8 @@ export class GetUncategorizedTransactions {
|
||||
.where('accountId', accountId)
|
||||
.where('categorized', false)
|
||||
.withGraphFetched('account')
|
||||
.pagination(0, 10);
|
||||
.orderBy('date', 'DESC')
|
||||
.pagination(0, 1000);
|
||||
|
||||
const data = await this.transformer.transform(
|
||||
tenantId,
|
||||
|
||||
@@ -8,6 +8,7 @@ export class UncategorizedTransactionTransformer extends Transformer {
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return [
|
||||
'formattedAmount',
|
||||
'formattedDate',
|
||||
'formattetDepositAmount',
|
||||
'formattedWithdrawalAmount',
|
||||
@@ -23,6 +24,17 @@ export class UncategorizedTransactionTransformer extends Transformer {
|
||||
return this.formatDate(transaction.date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted amount.
|
||||
* @param transaction
|
||||
* @returns {string}
|
||||
*/
|
||||
public formattedAmount(transaction) {
|
||||
return formatNumber(transaction.amount, {
|
||||
currencyCode: transaction.currencyCode,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted deposit amount.
|
||||
* @param transaction
|
||||
|
||||
@@ -55,7 +55,7 @@ export const transformCategorizeTransToCashflow = (
|
||||
referenceNo: categorizeDTO.referenceNo || uncategorizeModel.referenceNo,
|
||||
description: categorizeDTO.description || uncategorizeModel.description,
|
||||
cashflowAccountId: uncategorizeModel.accountId,
|
||||
creditAccountId: categorizeDTO.fromAccountId || categorizeDTO.toAccountId,
|
||||
creditAccountId: categorizeDTO.creditAccountId,
|
||||
exchangeRate: categorizeDTO.exchangeRate || 1,
|
||||
currencyCode: uncategorizeModel.currencyCode,
|
||||
amount: uncategorizeModel.amount,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
import { Classes } from '@blueprintjs/core';
|
||||
import { LoadingIndicator } from '../Indicator';
|
||||
|
||||
@@ -11,8 +12,8 @@ export function DrawerLoading({ loading, mount = false, children }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function DrawerBody({ children }) {
|
||||
return <div className={Classes.DRAWER_BODY}>{children}</div>;
|
||||
export function DrawerBody({ children, className }) {
|
||||
return <div className={clsx(Classes.DRAWER_BODY, className)}>{children}</div>;
|
||||
}
|
||||
|
||||
export * from './DrawerActionsBar';
|
||||
|
||||
@@ -26,12 +26,12 @@ const SelectButton = styled(Button)`
|
||||
position: relative;
|
||||
padding-right: 30px;
|
||||
|
||||
&.bp4-small{
|
||||
&.bp4-small {
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
&:not(.is-selected):not([class*='bp4-intent-']):not(.bp4-minimal) {
|
||||
color: #5c7080;
|
||||
color: #8f99a8;
|
||||
}
|
||||
&:after {
|
||||
content: '';
|
||||
|
||||
@@ -2,30 +2,55 @@
|
||||
import React from 'react';
|
||||
import { DrawerHeaderContent, DrawerLoading } from '@/components';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
import { useUncategorizedTransaction } from '@/hooks/query';
|
||||
import {
|
||||
useAccounts,
|
||||
useBranches,
|
||||
useUncategorizedTransaction,
|
||||
} from '@/hooks/query';
|
||||
import { useFeatureCan } from '@/hooks/state';
|
||||
import { Features } from '@/constants';
|
||||
|
||||
const CategorizeTransactionBootContext = React.createContext();
|
||||
|
||||
/**
|
||||
* Estimate detail provider.
|
||||
* Categorize transcation boot.
|
||||
*/
|
||||
function CategorizeTransactionBoot({ uncategorizedTransactionId, ...props }) {
|
||||
// Detarmines whether the feature is enabled.
|
||||
const { featureCan } = useFeatureCan();
|
||||
const isBranchFeatureCan = featureCan(Features.Branches);
|
||||
|
||||
// Fetches accounts list.
|
||||
const { isLoading: isAccountsLoading, data: accounts } = useAccounts();
|
||||
|
||||
// Fetches the branches list.
|
||||
const { data: branches, isLoading: isBranchesLoading } = useBranches(
|
||||
{},
|
||||
{ enabled: isBranchFeatureCan },
|
||||
);
|
||||
// Retrieves the uncategorized transaction.
|
||||
const {
|
||||
data: uncategorizedTransaction,
|
||||
isLoading: isUncategorizedTransactionLoading,
|
||||
} = useUncategorizedTransaction(uncategorizedTransactionId);
|
||||
|
||||
const provider = {
|
||||
uncategorizedTransactionId,
|
||||
uncategorizedTransaction,
|
||||
isUncategorizedTransactionLoading,
|
||||
branches,
|
||||
accounts,
|
||||
isBranchesLoading,
|
||||
isAccountsLoading,
|
||||
};
|
||||
const isLoading =
|
||||
isBranchesLoading || isUncategorizedTransactionLoading || isAccountsLoading;
|
||||
|
||||
return (
|
||||
<DrawerLoading loading={isUncategorizedTransactionLoading}>
|
||||
<DrawerLoading loading={isLoading}>
|
||||
<DrawerHeaderContent
|
||||
name={DRAWERS.CATEGORIZE_TRANSACTION}
|
||||
title={'Categorize Transaction'}
|
||||
subTitle={''}
|
||||
/>
|
||||
<CategorizeTransactionBootContext.Provider value={provider} {...props} />
|
||||
</DrawerLoading>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import styled from 'styled-components';
|
||||
import { DrawerBody } from '@/components';
|
||||
import { CategorizeTransactionBoot } from './CategorizeTransactionBoot';
|
||||
import { CategorizeTransactionForm } from './CategorizeTransactionForm';
|
||||
@@ -10,9 +11,14 @@ export default function CategorizeTransactionContent({
|
||||
<CategorizeTransactionBoot
|
||||
uncategorizedTransactionId={uncategorizedTransactionId}
|
||||
>
|
||||
<DrawerBody>
|
||||
<CategorizeTransactionDrawerBody>
|
||||
<CategorizeTransactionForm />
|
||||
</DrawerBody>
|
||||
</CategorizeTransactionDrawerBody>
|
||||
</CategorizeTransactionBoot>
|
||||
);
|
||||
}
|
||||
|
||||
export const CategorizeTransactionDrawerBody = styled(DrawerBody)`
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
// @ts-nocheck
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const Schema = Yup.object().shape({});
|
||||
const Schema = Yup.object().shape({
|
||||
amount: Yup.string().required().label('Amount'),
|
||||
exchangeRate: Yup.string().required().label('Exchange rate'),
|
||||
transactionType: Yup.string().required().label('Transaction type'),
|
||||
date: Yup.string().required().label('Date'),
|
||||
creditAccountId: Yup.string().required().label('Credit account'),
|
||||
referenceNo: Yup.string().optional().label('Reference No.'),
|
||||
description: Yup.string().optional().label('Description'),
|
||||
});
|
||||
|
||||
export const CreateCategorizeTransactionSchema = Schema;
|
||||
export const EditCategorizeTransactionSchema = Schema;
|
||||
|
||||
@@ -1,34 +1,57 @@
|
||||
// @ts-nocheck
|
||||
import { Formik, Form } from 'formik';
|
||||
import styled from 'styled-components';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import {
|
||||
EditCategorizeTransactionSchema,
|
||||
CreateCategorizeTransactionSchema,
|
||||
} from './CategorizeTransactionForm.schema';
|
||||
import { compose, transformToForm } from '@/utils';
|
||||
import { CreateCategorizeTransactionSchema } from './CategorizeTransactionForm.schema';
|
||||
import { CategorizeTransactionFormContent } from './CategorizeTransactionFormContent';
|
||||
import { CategorizeTransactionFormFooter } from './CategorizeTransactionFormFooter';
|
||||
|
||||
// Default initial form values.
|
||||
const defaultInitialValues = {};
|
||||
import { useCategorizeTransaction } from '@/hooks/query';
|
||||
import { useCategorizeTransactionBoot } from './CategorizeTransactionBoot';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
import {
|
||||
transformToCategorizeForm,
|
||||
defaultInitialValues,
|
||||
tranformToRequest,
|
||||
} from './_utils';
|
||||
import { compose } from '@/utils';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { AppToaster } from '@/components';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
|
||||
/**
|
||||
* Categorize cashflow transaction form dialog content.
|
||||
*/
|
||||
function CategorizeTransactionFormRoot({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const isNewMode = true;
|
||||
|
||||
// Form validation schema in create and edit mode.
|
||||
const validationSchema = isNewMode
|
||||
? CreateCategorizeTransactionSchema
|
||||
: EditCategorizeTransactionSchema;
|
||||
const { uncategorizedTransactionId, uncategorizedTransaction } =
|
||||
useCategorizeTransactionBoot();
|
||||
const { mutateAsync: categorizeTransaction } = useCategorizeTransaction();
|
||||
|
||||
// Callbacks handles form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {};
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
const transformedValues = tranformToRequest(values);
|
||||
|
||||
setSubmitting(true);
|
||||
categorizeTransaction([uncategorizedTransactionId, transformedValues])
|
||||
.then(() => {
|
||||
setSubmitting(false);
|
||||
closeDrawer(DRAWERS.CATEGORIZE_TRANSACTION);
|
||||
|
||||
AppToaster.show({
|
||||
message: 'The uncategorized transaction has been categorized.',
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
setSubmitting(false);
|
||||
AppToaster.show({
|
||||
message: 'Something went wrong!',
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
});
|
||||
};
|
||||
// Form initial values in create and edit mode.
|
||||
const initialValues = {
|
||||
...defaultInitialValues,
|
||||
@@ -37,23 +60,37 @@ function CategorizeTransactionFormRoot({
|
||||
* values such as `notes` come back from the API as null, so remove those
|
||||
* as well.
|
||||
*/
|
||||
...transformToForm({}, defaultInitialValues),
|
||||
...transformToCategorizeForm(uncategorizedTransaction),
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
validationSchema={validationSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<Form>
|
||||
<CategorizeTransactionFormContent />
|
||||
<CategorizeTransactionFormFooter />
|
||||
</Form>
|
||||
</Formik>
|
||||
<DivRoot>
|
||||
<Formik
|
||||
validationSchema={CreateCategorizeTransactionSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<Form>
|
||||
<CategorizeTransactionFormContent />
|
||||
<CategorizeTransactionFormFooter />
|
||||
</Form>
|
||||
</Formik>
|
||||
</DivRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export const CategorizeTransactionForm = compose(withDialogActions)(
|
||||
export const CategorizeTransactionForm = compose(withDrawerActions)(
|
||||
CategorizeTransactionFormRoot,
|
||||
);
|
||||
|
||||
const DivRoot = styled.div`
|
||||
.bp4-form-group .bp4-form-content {
|
||||
flex: 1 0;
|
||||
}
|
||||
.bp4-form-group .bp4-label {
|
||||
width: 140px;
|
||||
}
|
||||
.bp4-form-group {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,31 +1,39 @@
|
||||
// @ts-nocheck
|
||||
import { Position } from '@blueprintjs/core';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
AccountsSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FSelect,
|
||||
FSuggest,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { getAddMoneyInOptions } from '@/constants';
|
||||
import { FormGroup } from '@blueprintjs/core';
|
||||
import { FFormGroup, FSelect, FSuggest } from '@/components';
|
||||
import { getAddMoneyInOptions, getAddMoneyOutOptions } from '@/constants';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { useCategorizeTransactionBoot } from './CategorizeTransactionBoot';
|
||||
|
||||
// Retrieves the add money in button options.
|
||||
const AddMoneyInOptions = getAddMoneyInOptions();
|
||||
const MoneyInOptions = getAddMoneyInOptions();
|
||||
const MoneyOutOptions = getAddMoneyOutOptions();
|
||||
|
||||
const Title = styled('h3')``;
|
||||
const Title = styled('h3')`
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
color: #cd4246;
|
||||
`;
|
||||
|
||||
export function CategorizeTransactionFormContent() {
|
||||
const { uncategorizedTransaction } = useCategorizeTransactionBoot();
|
||||
|
||||
const transactionTypes = uncategorizedTransaction?.is_deposit_transaction
|
||||
? MoneyInOptions
|
||||
: MoneyOutOptions;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title>$22,583.00</Title>
|
||||
<FormGroup label={'Amount'} inline>
|
||||
<Title>{uncategorizedTransaction.formatted_amount}</Title>
|
||||
</FormGroup>
|
||||
|
||||
<FFormGroup name={'category'} label={'Category'} fastField inline>
|
||||
<FSuggest
|
||||
name={'transaction_type'}
|
||||
items={AddMoneyInOptions}
|
||||
<FSelect
|
||||
name={'transactionType'}
|
||||
items={transactionTypes}
|
||||
popoverProps={{ minimal: true }}
|
||||
valueAccessor={'value'}
|
||||
textAccessor={'name'}
|
||||
@@ -33,58 +41,56 @@ export function CategorizeTransactionFormContent() {
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'date'} label={'Date'} fastField inline>
|
||||
<FDateInput
|
||||
name={'date'}
|
||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||
formatDate={(date) => date.toLocaleDateString()}
|
||||
parseDate={(str) => new Date(str)}
|
||||
inputProps={{ fill: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'from_account_id'}
|
||||
label={'From Account'}
|
||||
fastField={true}
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'from_account_id'}
|
||||
items={[]}
|
||||
fastField={true}
|
||||
fill={true}
|
||||
allowCreate={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'toAccountId'}
|
||||
label={'To Account'}
|
||||
fastField={true}
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'to_account_id'}
|
||||
items={[]}
|
||||
fastField={true}
|
||||
fill={true}
|
||||
allowCreate={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'referenceNo'} label={'Reference No.'} fastField inline>
|
||||
<FInputGroup name={'reference_no'} fill />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'description'} label={'Description'} fastField inline>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
<CategorizeTransactionFormSubContent />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const CategorizeTransactionOtherIncome = React.lazy(
|
||||
() => import('./MoneyIn/CategorizeTransactionOtherIncome'),
|
||||
);
|
||||
|
||||
const CategorizeTransactionOwnerContribution = React.lazy(
|
||||
() => import('./MoneyIn/CategorizeTransactionOwnerContribution'),
|
||||
);
|
||||
|
||||
const CategorizeTransactionTransferFrom = React.lazy(
|
||||
() => import('./MoneyIn/CategorizeTransactionTransferFrom'),
|
||||
);
|
||||
|
||||
const CategorizeTransactionOtherExpense = React.lazy(
|
||||
() => import('./MoneyOut/CategorizeTransactionOtherExpense'),
|
||||
);
|
||||
|
||||
const CategorizeTransactionToAccount = React.lazy(
|
||||
() => import('./MoneyOut/CategorizeTransactionToAccount'),
|
||||
);
|
||||
|
||||
const CategorizeTransactionOwnerDrawings = React.lazy(
|
||||
() => import('./MoneyOut/CategorizeTransactionOwnerDrawings'),
|
||||
);
|
||||
|
||||
function CategorizeTransactionFormSubContent() {
|
||||
const { values } = useFormikContext();
|
||||
|
||||
// Other expense.
|
||||
if (values.transactionType === 'other_expense') {
|
||||
return <CategorizeTransactionOtherExpense />;
|
||||
// Owner contribution.
|
||||
} else if (values.transactionType === 'owner_contribution') {
|
||||
return <CategorizeTransactionOwnerContribution />;
|
||||
// Other Income.
|
||||
} else if (values.transactionType === 'other_income') {
|
||||
return <CategorizeTransactionOtherIncome />;
|
||||
// Transfer from account.
|
||||
} else if (values.transactionType === 'transfer_from_account') {
|
||||
return <CategorizeTransactionTransferFrom />;
|
||||
// Transfer to account.
|
||||
} else if (values.transactionType === 'transfer_to_account') {
|
||||
return <CategorizeTransactionToAccount />;
|
||||
// Owner drawings.
|
||||
} else if (values.transactionType === 'OwnerDrawing') {
|
||||
return <CategorizeTransactionOwnerDrawings />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,56 @@
|
||||
// @ts-nocheck
|
||||
import * as R from 'ramda';
|
||||
import { Button, Classes, Intent } from '@blueprintjs/core';
|
||||
import { useFormikContext } from 'formik';
|
||||
import styled from 'styled-components';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
import { Group } from '@/components';
|
||||
|
||||
function CategorizeTransactionFormFooterRoot({
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
const handleClose = () => {
|
||||
closeDrawer(DRAWERS.CATEGORIZE_TRANSACTION);
|
||||
};
|
||||
|
||||
export function CategorizeTransactionFormFooter() {
|
||||
return (
|
||||
<div>
|
||||
<Root>
|
||||
<div className={Classes.DRAWER_FOOTER}>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
// loading={isSubmitting}
|
||||
style={{ minWidth: '85px' }}
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Group spacing={10}>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
loading={isSubmitting}
|
||||
style={{ minWidth: '75px' }}
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
// disabled={isSubmitting}
|
||||
// onClick={onClose}
|
||||
style={{ minWidth: '75px' }}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
onClick={handleClose}
|
||||
style={{ minWidth: '75px' }}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</Group>
|
||||
</div>
|
||||
</div>
|
||||
</Root>
|
||||
);
|
||||
}
|
||||
|
||||
export const CategorizeTransactionFormFooter = R.compose(withDrawerActions)(
|
||||
CategorizeTransactionFormFooterRoot,
|
||||
);
|
||||
|
||||
const Root = styled.div`
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import { Position } from '@blueprintjs/core';
|
||||
import {
|
||||
AccountsSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { useCategorizeTransactionBoot } from '../CategorizeTransactionBoot';
|
||||
|
||||
export default function CategorizeTransactionOtherIncome() {
|
||||
const { accounts } = useCategorizeTransactionBoot();
|
||||
|
||||
return (
|
||||
<>
|
||||
<FFormGroup name={'date'} label={'Date'} fastField inline>
|
||||
<FDateInput
|
||||
name={'date'}
|
||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||
formatDate={(date) => date.toLocaleDateString()}
|
||||
parseDate={(str) => new Date(str)}
|
||||
inputProps={{ fill: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'debitAccountId'}
|
||||
label={'To Account'}
|
||||
fastField={true}
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'debitAccountId'}
|
||||
items={accounts}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
disabled
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'creditAccountId'}
|
||||
label={'Income Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'creditAccountId'}
|
||||
items={accounts}
|
||||
filterByRootTypes={['income']}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'referenceNo'} label={'Reference No.'} fastField inline>
|
||||
<FInputGroup name={'reference_no'} fill />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'description'} label={'Description'} fastField inline>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// @ts-nocheck
|
||||
import { Position } from '@blueprintjs/core';
|
||||
import {
|
||||
AccountsSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { useCategorizeTransactionBoot } from '../CategorizeTransactionBoot';
|
||||
|
||||
export default function CategorizeTransactionOwnerContribution() {
|
||||
const { accounts } = useCategorizeTransactionBoot();
|
||||
|
||||
return (
|
||||
<>
|
||||
<FFormGroup name={'date'} label={'Date'} fastField inline>
|
||||
<FDateInput
|
||||
name={'date'}
|
||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||
formatDate={(date) => date.toLocaleDateString()}
|
||||
parseDate={(str) => new Date(str)}
|
||||
inputProps={{ fill: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'debitAccountId'}
|
||||
label={'From Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'debitAccountId'}
|
||||
items={accounts}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
disabled
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'creditAccountId'}
|
||||
label={'Equity Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'creditAccountId'}
|
||||
items={accounts}
|
||||
filterByRootTypes={['equity']}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'referenceNo'} label={'Reference No.'} fastField inline>
|
||||
<FInputGroup name={'reference_no'} fill />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'description'} label={'Description'} fastField inline>
|
||||
<FTextArea name={'description'} growVertically large fill />
|
||||
</FFormGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import { Position } from '@blueprintjs/core';
|
||||
import {
|
||||
AccountsSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { useCategorizeTransactionBoot } from '../CategorizeTransactionBoot';
|
||||
|
||||
export default function CategorizeTransactionTransferFrom() {
|
||||
const { accounts } = useCategorizeTransactionBoot();
|
||||
|
||||
return (
|
||||
<>
|
||||
<FFormGroup name={'date'} label={'Date'} fastField inline>
|
||||
<FDateInput
|
||||
name={'date'}
|
||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||
formatDate={(date) => date.toLocaleDateString()}
|
||||
parseDate={(str) => new Date(str)}
|
||||
inputProps={{ fill: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'debitAccountId'}
|
||||
label={'From Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'debitAccountId'}
|
||||
items={accounts}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
disabled
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'creditAccountId'}
|
||||
label={'To Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'to_account_id'}
|
||||
items={accounts}
|
||||
filterByRootTypes={['asset']}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'referenceNo'} label={'Reference No.'} fastField inline>
|
||||
<FInputGroup name={'reference_no'} fill />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'description'} label={'Description'} fastField inline>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import { Position } from '@blueprintjs/core';
|
||||
import {
|
||||
AccountsSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { useCategorizeTransactionBoot } from '../CategorizeTransactionBoot';
|
||||
|
||||
export default function CategorizeTransactionOtherExpense() {
|
||||
const { accounts } = useCategorizeTransactionBoot();
|
||||
|
||||
return (
|
||||
<>
|
||||
<FFormGroup name={'date'} label={'Date'} fastField inline>
|
||||
<FDateInput
|
||||
name={'date'}
|
||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||
formatDate={(date) => date.toLocaleDateString()}
|
||||
parseDate={(str) => new Date(str)}
|
||||
inputProps={{ fill: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'debitAccountId'}
|
||||
label={'Payment Account'}
|
||||
fastField={true}
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'debitAccountId'}
|
||||
items={accounts}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
disabled
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'creditAccountId'}
|
||||
label={'Expense Account'}
|
||||
fastField={true}
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'creditAccountId'}
|
||||
items={accounts}
|
||||
filterByRootTypes={['expense']}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'referenceNo'} label={'Reference No.'} fastField inline>
|
||||
<FInputGroup name={'reference_no'} fill />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'description'} label={'Description'} fastField inline>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import { Position } from '@blueprintjs/core';
|
||||
import {
|
||||
AccountsSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { useCategorizeTransactionBoot } from '../CategorizeTransactionBoot';
|
||||
|
||||
export default function CategorizeTransactionOwnerDrawings() {
|
||||
const { accounts } = useCategorizeTransactionBoot();
|
||||
|
||||
return (
|
||||
<>
|
||||
<FFormGroup name={'date'} label={'Date'} fastField inline>
|
||||
<FDateInput
|
||||
name={'date'}
|
||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||
formatDate={(date) => date.toLocaleDateString()}
|
||||
parseDate={(str) => new Date(str)}
|
||||
inputProps={{ fill: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'debitAccountId'}
|
||||
label={'Debit Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'debitAccountId'}
|
||||
items={accounts}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
disabled
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'creditAccountId'}
|
||||
label={'Equity Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'creditAccountId'}
|
||||
items={accounts}
|
||||
filterByRootTypes={['equity']}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'referenceNo'} label={'Reference No.'} fastField inline>
|
||||
<FInputGroup name={'reference_no'} fill />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'description'} label={'Description'} fastField inline>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import { Position } from '@blueprintjs/core';
|
||||
import {
|
||||
AccountsSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FTextArea,
|
||||
} from '@/components';
|
||||
import { useCategorizeTransactionBoot } from '../CategorizeTransactionBoot';
|
||||
|
||||
export default function CategorizeTransactionToAccount() {
|
||||
const { accounts } = useCategorizeTransactionBoot();
|
||||
|
||||
return (
|
||||
<>
|
||||
<FFormGroup name={'date'} label={'Date'} fastField inline>
|
||||
<FDateInput
|
||||
name={'date'}
|
||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||
formatDate={(date) => date.toLocaleDateString()}
|
||||
parseDate={(str) => new Date(str)}
|
||||
inputProps={{ fill: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'debitAccountId'}
|
||||
label={'From Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'debitAccountId'}
|
||||
items={accounts}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
disabled
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={'creditAccountId'}
|
||||
label={'To Account'}
|
||||
fastField
|
||||
inline
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'creditAccountId'}
|
||||
items={accounts}
|
||||
filterByRootTypes={['assset']}
|
||||
fastField
|
||||
fill
|
||||
allowCreate
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'referenceNo'} label={'Reference No.'} fastField inline>
|
||||
<FInputGroup name={'reference_no'} fill />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'description'} label={'Description'} fastField inline>
|
||||
<FTextArea
|
||||
name={'description'}
|
||||
growVertically={true}
|
||||
large={true}
|
||||
fill={true}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// @ts-nocheck
|
||||
import { transformToForm, transfromToSnakeCase } from '@/utils';
|
||||
|
||||
// Default initial form values.
|
||||
export const defaultInitialValues = {
|
||||
amount: '',
|
||||
date: '',
|
||||
creditAccountId: '',
|
||||
debitAccountId: '',
|
||||
exchangeRate: '1',
|
||||
transactionType: '',
|
||||
referenceNo: '',
|
||||
description: '',
|
||||
};
|
||||
|
||||
export const transformToCategorizeForm = (uncategorizedTransaction) => {
|
||||
const defaultValues = {
|
||||
debitAccountId: uncategorizedTransaction.account_id,
|
||||
transactionType: uncategorizedTransaction.is_deposit_transaction
|
||||
? 'other_income'
|
||||
: 'other_expense',
|
||||
amount: uncategorizedTransaction.amount,
|
||||
date: uncategorizedTransaction.date,
|
||||
};
|
||||
return transformToForm(defaultValues, defaultInitialValues);
|
||||
};
|
||||
|
||||
|
||||
export const tranformToRequest = (formValues) => {
|
||||
return transfromToSnakeCase(formValues);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './CategorizeTransactionDrawer';
|
||||
@@ -231,3 +231,27 @@ export function useUncategorizedTransaction(
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Categorize the cashflow transaction.
|
||||
*/
|
||||
export function useCategorizeTransaction(props) {
|
||||
const queryClient = useQueryClient();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation(
|
||||
([id, values]) =>
|
||||
apiRequest.post(`cashflow/transactions/${id}/categorize`, values),
|
||||
{
|
||||
onSuccess: (res, id) => {
|
||||
// Invalidate queries.
|
||||
commonInvalidateQueries(queryClient);
|
||||
queryClient.invalidateQueries(t.CASHFLOW_UNCAATEGORIZED_TRANSACTION);
|
||||
queryClient.invalidateQueries(
|
||||
t.CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY,
|
||||
);
|
||||
},
|
||||
...props,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -202,7 +202,6 @@ const CASH_FLOW_ACCOUNTS = {
|
||||
'CASHFLOW_ACCOUNT_TRANSACTIONS_INFINITY',
|
||||
CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY:
|
||||
'CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY',
|
||||
|
||||
CASHFLOW_UNCAATEGORIZED_TRANSACTION: 'CASHFLOW_UNCAATEGORIZED_TRANSACTION',
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user