mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 06:10:31 +00:00
feat(banking): Filter uncategorized bank transactions
This commit is contained in:
@@ -167,11 +167,18 @@ export interface CategorizeTransactionAsExpenseDTO {
|
|||||||
export interface IGetUncategorizedTransactionsQuery {
|
export interface IGetUncategorizedTransactionsQuery {
|
||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
|
minDate?: Date;
|
||||||
|
maxDate?: Date;
|
||||||
|
minAmount?: number;
|
||||||
|
maxAmount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface IGetRecognizedTransactionsQuery {
|
export interface IGetRecognizedTransactionsQuery {
|
||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
accountId?: number;
|
accountId?: number;
|
||||||
|
minDate?: Date;
|
||||||
|
maxDate?: Date;
|
||||||
|
minAmount?: number;
|
||||||
|
maxAmount?: number;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable global-require */
|
/* eslint-disable global-require */
|
||||||
import * as R from 'ramda';
|
import moment from 'moment';
|
||||||
import { Model, ModelOptions, QueryContext, mixin } from 'objection';
|
import { Model, ModelOptions, QueryContext, mixin } from 'objection';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import ModelSettings from './ModelSetting';
|
import ModelSettings from './ModelSetting';
|
||||||
@@ -46,7 +46,7 @@ export default class UncategorizedCashflowTransaction extends mixin(
|
|||||||
'isDepositTransaction',
|
'isDepositTransaction',
|
||||||
'isWithdrawalTransaction',
|
'isWithdrawalTransaction',
|
||||||
'isRecognized',
|
'isRecognized',
|
||||||
'isExcluded'
|
'isExcluded',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +143,42 @@ export default class UncategorizedCashflowTransaction extends mixin(
|
|||||||
query.whereNull('categorizeRefType');
|
query.whereNull('categorizeRefType');
|
||||||
query.whereNull('categorizeRefId');
|
query.whereNull('categorizeRefId');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the not pending transactions.
|
||||||
|
*/
|
||||||
|
notPending(query) {
|
||||||
|
query.where('pending', false);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the pending transactions.
|
||||||
|
*/
|
||||||
|
pending(query) {
|
||||||
|
query.where('pending', true);
|
||||||
|
},
|
||||||
|
|
||||||
|
minAmount(query, minAmount) {
|
||||||
|
query.where('amount', '>=', minAmount);
|
||||||
|
},
|
||||||
|
|
||||||
|
maxAmount(query, maxAmount) {
|
||||||
|
query.where('amount', '<=', maxAmount);
|
||||||
|
},
|
||||||
|
|
||||||
|
toDate(query, toDate) {
|
||||||
|
const dateFormat = 'YYYY-MM-DD';
|
||||||
|
const _toDate = moment(toDate).endOf('day').format(dateFormat);
|
||||||
|
|
||||||
|
query.where('date', '<=', _toDate);
|
||||||
|
},
|
||||||
|
|
||||||
|
fromDate(query, fromDate) {
|
||||||
|
const dateFormat = 'YYYY-MM-DD';
|
||||||
|
const _fromDate = moment(fromDate).startOf('day').format(dateFormat);
|
||||||
|
|
||||||
|
query.where('date', '>=', _fromDate);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
|
||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
|
import moment from 'moment';
|
||||||
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { ExcludedBankTransactionsQuery } from './_types';
|
import { ExcludedBankTransactionsQuery } from './_types';
|
||||||
import { UncategorizedTransactionTransformer } from '@/services/Cashflow/UncategorizedTransactionTransformer';
|
import { UncategorizedTransactionTransformer } from '@/services/Cashflow/UncategorizedTransactionTransformer';
|
||||||
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
||||||
@@ -39,6 +40,18 @@ export class GetExcludedBankTransactionsService {
|
|||||||
if (_query.accountId) {
|
if (_query.accountId) {
|
||||||
q.where('account_id', _query.accountId);
|
q.where('account_id', _query.accountId);
|
||||||
}
|
}
|
||||||
|
if (_query.minDate) {
|
||||||
|
q.modify('fromDate', _query.minDate);
|
||||||
|
}
|
||||||
|
if (_query.maxDate) {
|
||||||
|
q.modify('toDate', _query.maxDate);
|
||||||
|
}
|
||||||
|
if (_query.minAmount) {
|
||||||
|
q.modify('minAmount', _query.minAmount);
|
||||||
|
}
|
||||||
|
if (_query.maxAmount) {
|
||||||
|
q.modify('maxAmount', _query.maxAmount);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.pagination(_query.page - 1, _query.pageSize);
|
.pagination(_query.page - 1, _query.pageSize);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ export interface ExcludedBankTransactionsQuery {
|
|||||||
page?: number;
|
page?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
accountId?: number;
|
accountId?: number;
|
||||||
|
minDate?: Date;
|
||||||
|
maxDate?: Date;
|
||||||
|
minAmount?: number;
|
||||||
|
maxAmount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBankTransactionUnexcludingEventPayload {
|
export interface IBankTransactionUnexcludingEventPayload {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class GetRecognizedTransactionsService {
|
|||||||
) {
|
) {
|
||||||
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const _filter = {
|
const _query = {
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
...filter,
|
...filter,
|
||||||
@@ -36,11 +36,23 @@ export class GetRecognizedTransactionsService {
|
|||||||
q.whereNotNull('recognizedTransactionId');
|
q.whereNotNull('recognizedTransactionId');
|
||||||
q.modify('notExcluded');
|
q.modify('notExcluded');
|
||||||
|
|
||||||
if (_filter.accountId) {
|
if (_query.accountId) {
|
||||||
q.where('accountId', _filter.accountId);
|
q.where('accountId', _query.accountId);
|
||||||
|
}
|
||||||
|
if (_query.minDate) {
|
||||||
|
q.modify('fromDate', _query.minDate);
|
||||||
|
}
|
||||||
|
if (_query.maxDate) {
|
||||||
|
q.modify('toDate', _query.maxDate);
|
||||||
|
}
|
||||||
|
if (_query.minAmount) {
|
||||||
|
q.modify('minAmount', _query.minAmount);
|
||||||
|
}
|
||||||
|
if (_query.maxAmount) {
|
||||||
|
q.modify('maxAmount', _query.maxAmount);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.pagination(_filter.page - 1, _filter.pageSize);
|
.pagination(_query.page - 1, _query.pageSize);
|
||||||
|
|
||||||
const data = await this.transformer.transform(
|
const data = await this.transformer.transform(
|
||||||
tenantId,
|
tenantId,
|
||||||
|
|||||||
@@ -60,6 +60,19 @@ export class GetUncategorizedTransactions {
|
|||||||
|
|
||||||
q.whereNull('matchedBankTransactions.id');
|
q.whereNull('matchedBankTransactions.id');
|
||||||
q.orderBy('date', 'DESC');
|
q.orderBy('date', 'DESC');
|
||||||
|
|
||||||
|
if (_query.minDate) {
|
||||||
|
q.modify('fromDate', _query.minDate);
|
||||||
|
}
|
||||||
|
if (_query.maxDate) {
|
||||||
|
q.modify('toDate', _query.maxDate);
|
||||||
|
}
|
||||||
|
if (_query.minAmount) {
|
||||||
|
q.modify('minAmount', _query.minAmount);
|
||||||
|
}
|
||||||
|
if (_query.maxAmount) {
|
||||||
|
q.modify('maxAmount', _query.maxAmount);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.pagination(_query.page - 1, _query.pageSize);
|
.pagination(_query.page - 1, _query.pageSize);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
import { useMemo } from 'react';
|
||||||
import { useAppQueryString } from '@/hooks';
|
import { useAppQueryString } from '@/hooks';
|
||||||
import { Group } from '@/components';
|
import { Box, FDateInput, FFormGroup, Group, Icon, Stack } from '@/components';
|
||||||
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
|
||||||
import { TagsControl } from '@/components/TagsControl';
|
import { TagsControl } from '@/components/TagsControl';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Classes,
|
||||||
|
FormGroup,
|
||||||
|
Intent,
|
||||||
|
Popover,
|
||||||
|
Position,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
|
import { Form, Formik } from 'formik';
|
||||||
|
|
||||||
export function AccountTransactionsUncategorizeFilter() {
|
export function AccountTransactionsUncategorizeFilter() {
|
||||||
const { bankAccountMetaSummary } = useAccountTransactionsContext();
|
const { bankAccountMetaSummary } = useAccountTransactionsContext();
|
||||||
@@ -48,3 +61,70 @@ export function AccountTransactionsUncategorizeFilter() {
|
|||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initialValues = {
|
||||||
|
fromDate: '',
|
||||||
|
toDate: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
fromDate: Yup.date()
|
||||||
|
.nullable()
|
||||||
|
.required('From Date is required')
|
||||||
|
.max(Yup.ref('toDate'), 'From Date cannot be after To Date'),
|
||||||
|
toDate: Yup.date()
|
||||||
|
.nullable()
|
||||||
|
.required('To Date is required')
|
||||||
|
.min(Yup.ref('fromDate'), 'To Date cannot be before From Date'),
|
||||||
|
});
|
||||||
|
|
||||||
|
function UncategorizedTransactionsDateFilter() {
|
||||||
|
const handleSubmit = () => {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
>
|
||||||
|
<Form>
|
||||||
|
<Stack>
|
||||||
|
<Group>
|
||||||
|
<FFormGroup name={'fromDate'} label={'From Date'}>
|
||||||
|
<FDateInput
|
||||||
|
name={'fromDate'}
|
||||||
|
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||||
|
formatDate={(date) => date.toLocaleDateString()}
|
||||||
|
parseDate={(str) => new Date(str)}
|
||||||
|
inputProps={{
|
||||||
|
fill: true,
|
||||||
|
leftElement: <Icon icon={'date-range'} />,
|
||||||
|
}}
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
/>
|
||||||
|
</FFormGroup>
|
||||||
|
|
||||||
|
<FormGroup label={'To Date'} name={'toDate'}>
|
||||||
|
<FDateInput
|
||||||
|
name={'toDate'}
|
||||||
|
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||||
|
formatDate={(date) => date.toLocaleDateString()}
|
||||||
|
parseDate={(str) => new Date(str)}
|
||||||
|
inputProps={{
|
||||||
|
fill: true,
|
||||||
|
leftElement: <Icon icon={'date-range'} />,
|
||||||
|
}}
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Group spacing={10}>
|
||||||
|
<Button intent={Intent.PRIMARY}>Filter</Button>
|
||||||
|
<Button>Cancel</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user