diff --git a/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts b/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts index 30b2a2326..d0953d8d8 100644 --- a/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts +++ b/packages/server/src/api/controllers/Cashflow/NewCashflowTransaction.ts @@ -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(), diff --git a/packages/server/src/interfaces/CashFlow.ts b/packages/server/src/interfaces/CashFlow.ts index aab3bb766..499c526b0 100644 --- a/packages/server/src/interfaces/CashFlow.ts +++ b/packages/server/src/interfaces/CashFlow.ts @@ -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; diff --git a/packages/server/src/models/Account.ts b/packages/server/src/models/Account.ts index c46f9e77b..7e0d8d6e4 100644 --- a/packages/server/src/models/Account.ts +++ b/packages/server/src/models/Account.ts @@ -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); }, }, }; diff --git a/packages/server/src/models/UncategorizedCashflowTransaction.ts b/packages/server/src/models/UncategorizedCashflowTransaction.ts index d8f3db543..cb5ebfeef 100644 --- a/packages/server/src/models/UncategorizedCashflowTransaction.ts +++ b/packages/server/src/models/UncategorizedCashflowTransaction.ts @@ -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 { + 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); } diff --git a/packages/server/src/services/Cashflow/CategorizeCashflowTransaction.ts b/packages/server/src/services/Cashflow/CategorizeCashflowTransaction.ts index da5b81419..3d19e1547 100644 --- a/packages/server/src/services/Cashflow/CategorizeCashflowTransaction.ts +++ b/packages/server/src/services/Cashflow/CategorizeCashflowTransaction.ts @@ -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, diff --git a/packages/server/src/services/Cashflow/GetCashflowTransactionsService.ts b/packages/server/src/services/Cashflow/GetCashflowTransactionsService.ts index 13852dd05..42bf7ca9e 100644 --- a/packages/server/src/services/Cashflow/GetCashflowTransactionsService.ts +++ b/packages/server/src/services/Cashflow/GetCashflowTransactionsService.ts @@ -31,6 +31,7 @@ export default class GetCashflowTransactionsService { .withGraphFetched('entries.cashflowAccount') .withGraphFetched('entries.creditAccount') .withGraphFetched('transactions.account') + .orderBy('date', 'DESC') .throwIfNotFound(); this.throwErrorCashflowTranscationNotFound(cashflowTransaction); diff --git a/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts b/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts index 9b273920f..41cfa2e85 100644 --- a/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts +++ b/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts @@ -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, diff --git a/packages/server/src/services/Cashflow/UncategorizedTransactionTransformer.ts b/packages/server/src/services/Cashflow/UncategorizedTransactionTransformer.ts index bf0a6a1cf..85d1a1fbb 100644 --- a/packages/server/src/services/Cashflow/UncategorizedTransactionTransformer.ts +++ b/packages/server/src/services/Cashflow/UncategorizedTransactionTransformer.ts @@ -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 diff --git a/packages/server/src/services/Cashflow/utils.ts b/packages/server/src/services/Cashflow/utils.ts index 9d76f1862..7957b73a9 100644 --- a/packages/server/src/services/Cashflow/utils.ts +++ b/packages/server/src/services/Cashflow/utils.ts @@ -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, diff --git a/packages/webapp/src/components/Drawer/DrawerBody.tsx b/packages/webapp/src/components/Drawer/DrawerBody.tsx index be7f34ac4..e6bab2b05 100644 --- a/packages/webapp/src/components/Drawer/DrawerBody.tsx +++ b/packages/webapp/src/components/Drawer/DrawerBody.tsx @@ -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
{children}
; +export function DrawerBody({ children, className }) { + return
{children}
; } export * from './DrawerActionsBar'; diff --git a/packages/webapp/src/components/Forms/Select.tsx b/packages/webapp/src/components/Forms/Select.tsx index cae52b1b8..c77c51ce2 100644 --- a/packages/webapp/src/components/Forms/Select.tsx +++ b/packages/webapp/src/components/Forms/Select.tsx @@ -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: ''; diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionBoot.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionBoot.tsx index 24af8cd26..6a7b8ea2b 100644 --- a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionBoot.tsx +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionBoot.tsx @@ -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 ( - + diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionContent.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionContent.tsx index 9bda3cdbc..7716e8beb 100644 --- a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionContent.tsx +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionContent.tsx @@ -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({ - + - + ); } + +export const CategorizeTransactionDrawerBody = styled(DrawerBody)` + padding: 20px; + background-color: #fff; +`; diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.schema.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.schema.tsx index f25c18a64..8c6d0eb72 100644 --- a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.schema.tsx +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.schema.tsx @@ -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; diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.tsx index 479be60bf..364c4111c 100644 --- a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.tsx +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionForm.tsx @@ -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 ( - -
- - - -
+ + +
+ + + +
+
); } -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; + } +`; diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormContent.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormContent.tsx index 9e5362f02..dfe1db6b0 100644 --- a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormContent.tsx +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormContent.tsx @@ -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 ( <> - $22,583.00 + + {uncategorizedTransaction.formatted_amount} + - - - date.toLocaleDateString()} - parseDate={(str) => new Date(str)} - inputProps={{ fill: true }} - /> - - - - - - - - - - - - - - - - - + ); } + +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 ; + // Owner contribution. + } else if (values.transactionType === 'owner_contribution') { + return ; + // Other Income. + } else if (values.transactionType === 'other_income') { + return ; + // Transfer from account. + } else if (values.transactionType === 'transfer_from_account') { + return ; + // Transfer to account. + } else if (values.transactionType === 'transfer_to_account') { + return ; + // Owner drawings. + } else if (values.transactionType === 'OwnerDrawing') { + return ; + } + return null; +} diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormFooter.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormFooter.tsx index acfaeec2c..3f8d7009b 100644 --- a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormFooter.tsx +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionFormFooter.tsx @@ -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 ( -
+
- + + - + +
-
+ ); } + +export const CategorizeTransactionFormFooter = R.compose(withDrawerActions)( + CategorizeTransactionFormFooterRoot, +); + +const Root = styled.div` + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: #fff; +`; diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionOtherIncome.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionOtherIncome.tsx new file mode 100644 index 000000000..2afc65f87 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionOtherIncome.tsx @@ -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 ( + <> + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ fill: true }} + /> + + + + + + + + + + + + + + + + + + + ); +} diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionOwnerContribution.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionOwnerContribution.tsx new file mode 100644 index 000000000..83b485c51 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionOwnerContribution.tsx @@ -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 ( + <> + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ fill: true }} + /> + + + + + + + + + + + + + + + + + + + ); +} diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionTransferFrom.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionTransferFrom.tsx new file mode 100644 index 000000000..57f2a1911 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyIn/CategorizeTransactionTransferFrom.tsx @@ -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 ( + <> + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ fill: true }} + /> + + + + + + + + + + + + + + + + + + + ); +} diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionOtherExpense.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionOtherExpense.tsx new file mode 100644 index 000000000..b85436e17 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionOtherExpense.tsx @@ -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 ( + <> + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ fill: true }} + /> + + + + + + + + + + + + + + + + + + + ); +} diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionOwnerDrawings.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionOwnerDrawings.tsx new file mode 100644 index 000000000..e39235fd9 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionOwnerDrawings.tsx @@ -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 ( + <> + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ fill: true }} + /> + + + + + + + + + + + + + + + + + + + ); +} diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionToAccount.tsx b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionToAccount.tsx new file mode 100644 index 000000000..4e4545e52 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/MoneyOut/CategorizeTransactionToAccount.tsx @@ -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 ( + <> + + date.toLocaleDateString()} + parseDate={(str) => new Date(str)} + inputProps={{ fill: true }} + /> + + + + + + + + + + + + + + + + + + + ); +} diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/_utils.ts b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/_utils.ts new file mode 100644 index 000000000..9fedc3678 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/_utils.ts @@ -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); +}; \ No newline at end of file diff --git a/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/index.ts b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/index.ts new file mode 100644 index 000000000..bff919dc5 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/index.ts @@ -0,0 +1 @@ +export * from './CategorizeTransactionDrawer'; \ No newline at end of file diff --git a/packages/webapp/src/hooks/query/cashflowAccounts.tsx b/packages/webapp/src/hooks/query/cashflowAccounts.tsx index 179317f2f..3a225db58 100644 --- a/packages/webapp/src/hooks/query/cashflowAccounts.tsx +++ b/packages/webapp/src/hooks/query/cashflowAccounts.tsx @@ -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, + }, + ); +} diff --git a/packages/webapp/src/hooks/query/types.tsx b/packages/webapp/src/hooks/query/types.tsx index 1d8d2d7a8..5446282e2 100644 --- a/packages/webapp/src/hooks/query/types.tsx +++ b/packages/webapp/src/hooks/query/types.tsx @@ -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', };