feat: remove uncategorized transaction from expenses

This commit is contained in:
Ahmed Bouhuolia
2024-03-07 20:58:44 +02:00
parent b9a00418fa
commit 83fbb7225d
12 changed files with 53 additions and 110 deletions

View File

@@ -1,9 +1,7 @@
import { Service, Inject } from 'typedi'; import { Service, Inject } from 'typedi';
import { Router, Request, Response, NextFunction } from 'express'; import { Router, Request, Response, NextFunction } from 'express';
import { param, query } from 'express-validator'; import { query } from 'express-validator';
import GetCashflowAccountsService from '@/services/Cashflow/GetCashflowAccountsService';
import BaseController from '../BaseController'; import BaseController from '../BaseController';
import GetCashflowTransactionsService from '@/services/Cashflow/GetCashflowTransactionsService';
import { ServiceError } from '@/exceptions'; import { ServiceError } from '@/exceptions';
import CheckPolicies from '@/api/middleware/CheckPolicies'; import CheckPolicies from '@/api/middleware/CheckPolicies';
import { AbilitySubject, CashflowAction } from '@/interfaces'; import { AbilitySubject, CashflowAction } from '@/interfaces';

View File

@@ -2,7 +2,6 @@ import { Service, Inject } from 'typedi';
import { Router, Request, Response, NextFunction } from 'express'; import { Router, Request, Response, NextFunction } from 'express';
import { param } from 'express-validator'; import { param } from 'express-validator';
import BaseController from '../BaseController'; import BaseController from '../BaseController';
import GetCashflowTransactionsService from '@/services/Cashflow/GetCashflowTransactionsService';
import { ServiceError } from '@/exceptions'; import { ServiceError } from '@/exceptions';
import CheckPolicies from '@/api/middleware/CheckPolicies'; import CheckPolicies from '@/api/middleware/CheckPolicies';
import { AbilitySubject, CashflowAction } from '@/interfaces'; import { AbilitySubject, CashflowAction } from '@/interfaces';
@@ -47,7 +46,6 @@ export default class GetCashflowAccounts extends BaseController {
const cashflowTransaction = await this.cashflowApplication.getTransaction( const cashflowTransaction = await this.cashflowApplication.getTransaction(
tenantId, tenantId,
transactionId transactionId
); );
return res.status(200).send({ return res.status(200).send({

View File

@@ -1,11 +0,0 @@
exports.up = function (knex) {
return knex.schema.table('expenses_transactions', (table) => {
table
.integer('categorized_transaction_id')
.unsigned()
.references('id')
.inTable('uncategorized_cashflow_transactions');
});
};
exports.down = function (knex) {};

View File

@@ -182,7 +182,6 @@ export default class Expense extends mixin(TenantModel, [
const ExpenseCategory = require('models/ExpenseCategory'); const ExpenseCategory = require('models/ExpenseCategory');
const Media = require('models/Media'); const Media = require('models/Media');
const Branch = require('models/Branch'); const Branch = require('models/Branch');
const UncategorizedCashflowTransaction = require('models/UncategorizedCashflowTransaction');
return { return {
paymentAccount: { paymentAccount: {
@@ -235,18 +234,6 @@ export default class Expense extends mixin(TenantModel, [
query.where('model_name', 'Expense'); query.where('model_name', 'Expense');
}, },
}, },
/**
* Retrieves the related uncategorized cashflow transaction.
*/
categorized: {
relation: Model.BelongsToOneRelation,
modelClass: UncategorizedCashflowTransaction.default,
join: {
from: 'expenses_transactions.categorizedTransactionId',
to: 'uncategorized_cashflow_transactions.id',
},
}
}; };
} }

View File

@@ -4,7 +4,11 @@ import { Model, ModelOptions, QueryContext } from 'objection';
import Account from './Account'; import Account from './Account';
export default class UncategorizedCashflowTransaction extends TenantModel { export default class UncategorizedCashflowTransaction extends TenantModel {
amount: number; id!: number;
amount!: number;
categorized!: boolean;
accountId!: number;
/** /**
* Table name. * Table name.
*/ */
@@ -19,6 +23,18 @@ export default class UncategorizedCashflowTransaction extends TenantModel {
return ['createdAt', 'updatedAt']; return ['createdAt', 'updatedAt'];
} }
/**
* Virtual attributes.
*/
static get virtualAttributes() {
return [
'withdrawal',
'deposit',
'isDepositTransaction',
'isWithdrawalTransaction',
];
}
/** /**
* Retrieves the withdrawal amount. * Retrieves the withdrawal amount.
* @returns {number} * @returns {number}
@@ -49,18 +65,6 @@ export default class UncategorizedCashflowTransaction extends TenantModel {
return 0 < this.withdrawal; return 0 < this.withdrawal;
} }
/**
* Virtual attributes.
*/
static get virtualAttributes() {
return [
'withdrawal',
'deposit',
'isDepositTransaction',
'isWithdrawalTransaction',
];
}
/** /**
* Relationship mapping. * Relationship mapping.
*/ */
@@ -83,40 +87,54 @@ export default class UncategorizedCashflowTransaction extends TenantModel {
} }
/** /**
* * Updates the count of uncategorized transactions for the associated account
* @param queryContext * based on the specified operation.
* @param {QueryContext} queryContext - The query context for the transaction.
* @param {boolean} increment - Indicates whether to increment or decrement the count.
*/
private async updateUncategorizedTransactionCount(
queryContext: QueryContext,
increment: boolean
) {
const operation = increment ? 'increment' : 'decrement';
const amount = increment ? 1 : -1;
await Account.query(queryContext.transaction)
.findById(this.accountId)
[operation]('uncategorized_transactions', amount);
}
/**
* Runs after insert.
* @param {QueryContext} queryContext
*/ */
public async $afterInsert(queryContext) { public async $afterInsert(queryContext) {
await super.$afterInsert(queryContext); await super.$afterInsert(queryContext);
await this.updateUncategorizedTransactionCount(queryContext, true);
// Increments the uncategorized transactions count of the associated account.
await Account.query(queryContext.transaction)
.findById(this.accountId)
.increment('uncategorized_transactions', 1);
} }
/**
* Runs after update.
* @param {ModelOptions} opt
* @param {QueryContext} queryContext
*/
public async $afterUpdate( public async $afterUpdate(
opt: ModelOptions, opt: ModelOptions,
queryContext: QueryContext queryContext: QueryContext
): void | Promise<any> { ): Promise<any> {
await super.$afterUpdate(opt, queryContext); await super.$afterUpdate(opt, queryContext);
if (this.id && this.categorized) { if (this.id && this.categorized) {
await Account.query(queryContext.transaction) await this.updateUncategorizedTransactionCount(queryContext, false);
.findById(this.accountId)
.decrement('uncategorized_transactions', 1);
} }
} }
/** /**
* * Runs after delete.
* @param queryContext * @param {QueryContext} queryContext
*/ */
public async $afterDelete(queryContext) { public async $afterDelete(queryContext: QueryContext) {
await super.$afterDelete(queryContext); await super.$afterDelete(queryContext);
await this.updateUncategorizedTransactionCount(queryContext, false);
await Account.query(queryContext.transaction)
.findById(this.accountId)
.decrement('uncategorized_transactions', 1);
} }
} }

View File

@@ -8,7 +8,6 @@ import {
transformPlaidAccountToCreateAccount, transformPlaidAccountToCreateAccount,
transformPlaidTrxsToCashflowCreate, transformPlaidTrxsToCashflowCreate,
} from './utils'; } from './utils';
import NewCashflowTransactionService from '@/services/Cashflow/NewCashflowTransactionService';
import { DeleteCashflowTransaction } from '@/services/Cashflow/DeleteCashflowTransactionService'; import { DeleteCashflowTransaction } from '@/services/Cashflow/DeleteCashflowTransactionService';
import HasTenancyService from '@/services/Tenancy/TenancyService'; import HasTenancyService from '@/services/Tenancy/TenancyService';
import { CashflowApplication } from '@/services/Cashflow/CashflowApplication'; import { CashflowApplication } from '@/services/Cashflow/CashflowApplication';
@@ -26,9 +25,6 @@ export class PlaidSyncDb {
@Inject() @Inject()
private cashflowApp: CashflowApplication; private cashflowApp: CashflowApplication;
@Inject()
private createCashflowTransactionService: NewCashflowTransactionService;
@Inject() @Inject()
private deleteCashflowTransactionService: DeleteCashflowTransaction; private deleteCashflowTransactionService: DeleteCashflowTransaction;

View File

@@ -1,9 +0,0 @@
import { Service } from 'typedi';
import { UncategorizeCashflowTransaction } from './UncategorizeCashflowTransaction';
@Service()
export class UncategorizeTransactionByRef {
private uncategorizeTransactionService: UncategorizeCashflowTransaction;
public uncategorize(tenantId: number, refId: number, refType: string) {}
}

View File

@@ -1,6 +1,5 @@
// @ts-nocheck // @ts-nocheck
import React, { Suspense } from 'react'; import React, { Suspense } from 'react';
import styled from 'styled-components';
import { Spinner } from '@blueprintjs/core'; import { Spinner } from '@blueprintjs/core';
import '@/style/pages/CashFlow/AccountTransactions/List.scss'; import '@/style/pages/CashFlow/AccountTransactions/List.scss';

View File

@@ -1,33 +0,0 @@
// @ts-nocheck
import React, { lazy } from 'react';
import { Drawer, DrawerSuspense } from '@/components';
import withDrawers from '@/containers/Drawer/withDrawers';
import { compose } from '@/utils';
const AccountDrawerContent = lazy(() => import('./AccountDrawerContent'));
/**
* Categorize the uncategorized transaction drawer.
*/
function CategorizeTransactionDrawer({
name,
// #withDrawer
isOpen,
payload: { uncategorizedTranasctionId },
}) {
return (
<Drawer
isOpen={isOpen}
name={name}
style={{ minWidth: '700px', maxWidth: '900px' }}
size={'65%'}
>
<DrawerSuspense>
<AccountDrawerContent name={name} accountId={accountId} />
</DrawerSuspense>
</Drawer>
);
}
export default compose(withDrawers())(AccountDrawer);

View File

@@ -1,7 +1,6 @@
// @ts-nocheck // @ts-nocheck
import { Formik, Form } from 'formik'; import { Formik, Form } from 'formik';
import styled from 'styled-components'; import styled from 'styled-components';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { CreateCategorizeTransactionSchema } from './CategorizeTransactionForm.schema'; import { CreateCategorizeTransactionSchema } from './CategorizeTransactionForm.schema';
import { CategorizeTransactionFormContent } from './CategorizeTransactionFormContent'; import { CategorizeTransactionFormContent } from './CategorizeTransactionFormContent';
import { CategorizeTransactionFormFooter } from './CategorizeTransactionFormFooter'; import { CategorizeTransactionFormFooter } from './CategorizeTransactionFormFooter';

View File

@@ -2,7 +2,7 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { FormGroup } from '@blueprintjs/core'; import { FormGroup } from '@blueprintjs/core';
import { FFormGroup, FSelect, FSuggest } from '@/components'; import { FFormGroup, FSelect, } from '@/components';
import { getAddMoneyInOptions, getAddMoneyOutOptions } from '@/constants'; import { getAddMoneyInOptions, getAddMoneyOutOptions } from '@/constants';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import { useCategorizeTransactionBoot } from './CategorizeTransactionBoot'; import { useCategorizeTransactionBoot } from './CategorizeTransactionBoot';

View File

@@ -213,7 +213,8 @@ export function useRefreshCashflowTransactions() {
} }
/** /**
* * Retrieves specific uncategorized transaction.
* @param {number} uncategorizedTranasctionId -
*/ */
export function useUncategorizedTransaction( export function useUncategorizedTransaction(
uncategorizedTranasctionId: nunber, uncategorizedTranasctionId: nunber,