From 6b6b73b77cd86875ebcf5a8bec7fb3ea89ac5606 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 17 Jul 2024 15:56:05 +0200 Subject: [PATCH 1/8] feat: send signup event to Loops (#531) * feat: send signup event to Loops * feat: fix --- packages/server/src/config/index.ts | 4 ++ packages/server/src/loaders/eventEmitter.ts | 4 ++ .../services/Loops/LoopsEventsSubscriber.ts | 51 +++++++++++++++++++ packages/server/src/subscribers/events.ts | 7 +++ 4 files changed, 66 insertions(+) create mode 100644 packages/server/src/services/Loops/LoopsEventsSubscriber.ts diff --git a/packages/server/src/config/index.ts b/packages/server/src/config/index.ts index 8172ddace..b8a862343 100644 --- a/packages/server/src/config/index.ts +++ b/packages/server/src/config/index.ts @@ -237,4 +237,8 @@ module.exports = { endpoint: process.env.S3_ENDPOINT, bucket: process.env.S3_BUCKET || 'bigcapital-documents', }, + + loops: { + apiKey: process.env.LOOPS_API_KEY, + }, }; diff --git a/packages/server/src/loaders/eventEmitter.ts b/packages/server/src/loaders/eventEmitter.ts index 8595bed55..9e2ae276e 100644 --- a/packages/server/src/loaders/eventEmitter.ts +++ b/packages/server/src/loaders/eventEmitter.ts @@ -113,6 +113,7 @@ import { UnlinkBankRuleOnDeleteBankRule } from '@/services/Banking/Rules/events/ import { DecrementUncategorizedTransactionOnMatching } from '@/services/Banking/Matching/events/DecrementUncategorizedTransactionsOnMatch'; import { DecrementUncategorizedTransactionOnExclude } from '@/services/Banking/Exclude/events/DecrementUncategorizedTransactionOnExclude'; import { DecrementUncategorizedTransactionOnCategorize } from '@/services/Cashflow/subscribers/DecrementUncategorizedTransactionOnCategorize'; +import { LoopsEventsSubscriber } from '@/services/Loops/LoopsEventsSubscriber'; export default () => { return new EventPublisher(); @@ -274,5 +275,8 @@ export const susbcribers = () => { // Plaid RecognizeSyncedBankTranasctions, + + // Loops + LoopsEventsSubscriber ]; }; diff --git a/packages/server/src/services/Loops/LoopsEventsSubscriber.ts b/packages/server/src/services/Loops/LoopsEventsSubscriber.ts new file mode 100644 index 000000000..33fe56e1a --- /dev/null +++ b/packages/server/src/services/Loops/LoopsEventsSubscriber.ts @@ -0,0 +1,51 @@ +import axios from 'axios'; +import config from '@/config'; +import { IAuthSignUpVerifiedEventPayload } from '@/interfaces'; +import events from '@/subscribers/events'; +import { SystemUser } from '@/system/models'; + +export class LoopsEventsSubscriber { + /** + * Constructor method. + */ + public attach(bus) { + bus.subscribe( + events.auth.signUpConfirmed, + this.triggerEventOnSignupVerified.bind(this) + ); + } + + /** + * Once the user verified sends the event to the Loops. + * @param {IAuthSignUpVerifiedEventPayload} param0 + */ + public async triggerEventOnSignupVerified({ + email, + userId, + }: IAuthSignUpVerifiedEventPayload) { + // Can't continue since the Loops the api key is not configured. + if (!config.loops.apiKey) { + return; + } + const user = await SystemUser.query().findById(userId); + + const options = { + method: 'POST', + url: 'https://app.loops.so/api/v1/events/send', + headers: { + Authorization: `Bearer ${config.loops.apiKey}`, + 'Content-Type': 'application/json', + }, + data: { + email, + userId, + firstName: user.firstName, + lastName: user.lastName, + eventName: 'USER_VERIFIED', + eventProperties: {}, + mailingLists: {}, + }, + }; + await axios(options); + } +} diff --git a/packages/server/src/subscribers/events.ts b/packages/server/src/subscribers/events.ts index 711dbce35..e90aeb309 100644 --- a/packages/server/src/subscribers/events.ts +++ b/packages/server/src/subscribers/events.ts @@ -40,6 +40,13 @@ export default { baseCurrencyUpdated: 'onOrganizationBaseCurrencyUpdated', }, + /** + * User subscription events. + */ + subscription: { + onSubscribed: 'onOrganizationSubscribed', + }, + /** * Tenants managment service. */ From fe214b1b2de0f7871b516aab8226b5521eedd73a Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 17 Jul 2024 16:53:47 +0200 Subject: [PATCH 2/8] feat: push CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e3926cfb..d70e73457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to Bigcapital server-side will be in this file. +## [v0.18.0] - 10-08-2024 + +* feat: Bank rules for automated categorization by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511 +* feat: Categorize & match bank transaction by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511 +* feat: Reconcile match transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/522 +* fix: Issues in matching transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/523 +* fix: Cashflow transactions types by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/524 + ## [v0.17.5] - 17-06-2024 * fix: Balance sheet and P/L nested accounts by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/501 From 51471ed000ea3e76060801f273f6762ee0cd70d9 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 17 Jul 2024 23:19:59 +0200 Subject: [PATCH 3/8] feat: exclude bank transactions in bulk --- .../ExcludeBankTransactionsController.ts | 77 +++++++++++- .../Exclude/ExcludeBankTransactions.ts | 31 +++++ .../ExcludeBankTransactionsApplication.ts | 40 ++++++ .../Exclude/UnexcludeBankTransactions.ts | 31 +++++ .../AccountTransactionsActionsBar.tsx | 92 ++++++++++++++ .../AccountTransactionsUncategorizedTable.tsx | 9 ++ .../ExcludedTransactionsTable.tsx | 25 +++- .../AccountExcludedTransactions.tsx | 31 ++++- .../AccountUncategorizedTransactionsAll.tsx | 24 +++- .../src/containers/CashFlow/withBanking.ts | 5 + .../containers/CashFlow/withBankingActions.ts | 28 +++++ packages/webapp/src/hooks/query/bank-rules.ts | 116 ++++++++++++++---- .../src/store/banking/banking.reducer.ts | 31 +++++ 13 files changed, 504 insertions(+), 36 deletions(-) create mode 100644 packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts create mode 100644 packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts diff --git a/packages/server/src/api/controllers/Banking/ExcludeBankTransactionsController.ts b/packages/server/src/api/controllers/Banking/ExcludeBankTransactionsController.ts index 79a6c7336..9d4ddec22 100644 --- a/packages/server/src/api/controllers/Banking/ExcludeBankTransactionsController.ts +++ b/packages/server/src/api/controllers/Banking/ExcludeBankTransactionsController.ts @@ -1,8 +1,9 @@ import { Inject, Service } from 'typedi'; -import { param } from 'express-validator'; -import { NextFunction, Request, Response, Router, query } from 'express'; +import { body, param, query } from 'express-validator'; +import { NextFunction, Request, Response, Router } from 'express'; import BaseController from '../BaseController'; import { ExcludeBankTransactionsApplication } from '@/services/Banking/Exclude/ExcludeBankTransactionsApplication'; +import { map, parseInt, trim } from 'lodash'; @Service() export class ExcludeBankTransactionsController extends BaseController { @@ -15,9 +16,21 @@ export class ExcludeBankTransactionsController extends BaseController { public router() { const router = Router(); + router.put( + '/transactions/exclude', + [body('ids').exists()], + this.validationResult, + this.excludeBulkBankTransactions.bind(this) + ); + router.put( + '/transactions/unexclude', + [body('ids').exists()], + this.validationResult, + this.unexcludeBulkBankTransactins.bind(this) + ); router.put( '/transactions/:transactionId/exclude', - [param('transactionId').exists()], + [param('transactionId').exists().toInt()], this.validationResult, this.excludeBankTransaction.bind(this) ); @@ -94,6 +107,63 @@ export class ExcludeBankTransactionsController extends BaseController { } } + /** + * Exclude bank transactions in bulk. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next + */ + private async excludeBulkBankTransactions( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; + const { ids } = this.matchedBodyData(req); + + try { + await this.excludeBankTransactionApp.excludeBankTransactions( + tenantId, + ids + ); + return res.status(200).send({ + message: 'The given bank transactions have been excluded', + ids, + }); + } catch (error) { + next(error); + } + } + + /** + * Unexclude the given bank transactions in bulk. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next + * @returns {Promise} + */ + private async unexcludeBulkBankTransactins( + req: Request, + res: Response, + next: NextFunction + ): Promise { + const { tenantId } = req; + const { ids } = this.matchedBodyData(req); + + try { + await this.excludeBankTransactionApp.unexcludeBankTransactions( + tenantId, + ids + ); + return res.status(200).send({ + message: 'The given bank transactions have been excluded', + ids, + }); + } catch (error) { + next(error); + } + } + /** * Retrieves the excluded uncategorized bank transactions. * @param {Request} req @@ -109,7 +179,6 @@ export class ExcludeBankTransactionsController extends BaseController { const { tenantId } = req; const filter = this.matchedBodyData(req); - console.log('123'); try { const data = await this.excludeBankTransactionApp.getExcludedBankTransactions( diff --git a/packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts b/packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts new file mode 100644 index 000000000..abf6bd434 --- /dev/null +++ b/packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts @@ -0,0 +1,31 @@ +import { Inject, Service } from 'typedi'; +import { ExcludeBankTransaction } from './ExcludeBankTransaction'; +import PromisePool from '@supercharge/promise-pool'; +import { castArray } from 'lodash'; + +@Service() +export class ExcludeBankTransactions { + @Inject() + private excludeBankTransaction: ExcludeBankTransaction; + + /** + * Exclude bank transactions in bulk. + * @param {number} tenantId + * @param {number} bankTransactionIds + */ + public async excludeBankTransactions( + tenantId: number, + bankTransactionIds: Array | number + ) { + const _bankTransactionIds = castArray(bankTransactionIds); + + await PromisePool.withConcurrency(1) + .for(_bankTransactionIds) + .process(async (bankTransactionId: number) => { + return this.excludeBankTransaction.excludeBankTransaction( + tenantId, + bankTransactionId + ); + }); + } +} diff --git a/packages/server/src/services/Banking/Exclude/ExcludeBankTransactionsApplication.ts b/packages/server/src/services/Banking/Exclude/ExcludeBankTransactionsApplication.ts index a87b63815..621652d86 100644 --- a/packages/server/src/services/Banking/Exclude/ExcludeBankTransactionsApplication.ts +++ b/packages/server/src/services/Banking/Exclude/ExcludeBankTransactionsApplication.ts @@ -3,6 +3,8 @@ import { ExcludeBankTransaction } from './ExcludeBankTransaction'; import { UnexcludeBankTransaction } from './UnexcludeBankTransaction'; import { GetExcludedBankTransactionsService } from './GetExcludedBankTransactions'; import { ExcludedBankTransactionsQuery } from './_types'; +import { UnexcludeBankTransactions } from './UnexcludeBankTransactions'; +import { ExcludeBankTransactions } from './ExcludeBankTransactions'; @Service() export class ExcludeBankTransactionsApplication { @@ -15,6 +17,12 @@ export class ExcludeBankTransactionsApplication { @Inject() private getExcludedBankTransactionsService: GetExcludedBankTransactionsService; + @Inject() + private excludeBankTransactionsService: ExcludeBankTransactions; + + @Inject() + private unexcludeBankTransactionsService: UnexcludeBankTransactions; + /** * Marks a bank transaction as excluded. * @param {number} tenantId - The ID of the tenant. @@ -56,4 +64,36 @@ export class ExcludeBankTransactionsApplication { filter ); } + + /** + * Exclude the given bank transactions in bulk. + * @param {number} tenantId + * @param {Array | number} bankTransactionIds + * @returns {Promise} + */ + public excludeBankTransactions( + tenantId: number, + bankTransactionIds: Array | number + ): Promise { + return this.excludeBankTransactionsService.excludeBankTransactions( + tenantId, + bankTransactionIds + ); + } + + /** + * Exclude the given bank transactions in bulk. + * @param {number} tenantId + * @param {Array | number} bankTransactionIds + * @returns {Promise} + */ + public unexcludeBankTransactions( + tenantId: number, + bankTransactionIds: Array | number + ): Promise { + return this.unexcludeBankTransactionsService.unexcludeBankTransactions( + tenantId, + bankTransactionIds + ); + } } diff --git a/packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts b/packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts new file mode 100644 index 000000000..840eb6259 --- /dev/null +++ b/packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts @@ -0,0 +1,31 @@ +import { Inject, Service } from 'typedi'; +import PromisePool from '@supercharge/promise-pool'; +import { UnexcludeBankTransaction } from './UnexcludeBankTransaction'; +import { castArray } from 'lodash'; + +@Service() +export class UnexcludeBankTransactions { + @Inject() + private unexcludeBankTransaction: UnexcludeBankTransaction; + + /** + * Unexclude bank transactions in bulk. + * @param {number} tenantId + * @param {number} bankTransactionIds + */ + public async unexcludeBankTransactions( + tenantId: number, + bankTransactionIds: Array | number + ) { + const _bankTransactionIds = castArray(bankTransactionIds); + + await PromisePool.withConcurrency(1) + .for(_bankTransactionIds) + .process(async (bankTransactionId: number) => { + return this.unexcludeBankTransaction.unexcludeBankTransaction( + tenantId, + bankTransactionId + ); + }); + } +} diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx index b5db2eb78..7ca9abc37 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx @@ -11,6 +11,7 @@ import { MenuItem, PopoverInteractionKind, Position, + Intent, } from '@blueprintjs/core'; import { useHistory } from 'react-router-dom'; import { @@ -18,6 +19,7 @@ import { DashboardActionsBar, DashboardRowsHeightButton, FormattedMessage as T, + AppToaster, } from '@/components'; import { CashFlowMenuItems } from './utils'; @@ -33,6 +35,13 @@ import withSettings from '@/containers/Settings/withSettings'; import withSettingsActions from '@/containers/Settings/withSettingsActions'; import { compose } from '@/utils'; +import { withBanking } from '../withBanking'; +import { isEmpty } from 'lodash'; +import { + useExcludeUncategorizedTransactions, + useUnexcludeUncategorizedTransaction, + useUnexcludeUncategorizedTransactions, +} from '@/hooks/query/bank-rules'; function AccountTransactionsActionsBar({ // #withDialogActions @@ -43,6 +52,10 @@ function AccountTransactionsActionsBar({ // #withSettingsActions addSetting, + + // #withBanking + uncategorizedTransationsIdsSelected, + excludedTransactionsIdsSelected, }) { const history = useHistory(); const { accountId } = useAccountTransactionsContext(); @@ -87,6 +100,54 @@ function AccountTransactionsActionsBar({ refresh(); }; + const { + mutateAsync: excludeUncategorizedTransactions, + isLoading: isExcludingLoading, + } = useExcludeUncategorizedTransactions(); + + const { + mutateAsync: unexcludeUncategorizedTransactions, + isLoading: isUnexcludingLoading, + } = useUnexcludeUncategorizedTransactions(); + + // Handles the exclude uncategorized transactions in bulk. + const handleExcludeUncategorizedBtnClick = () => { + excludeUncategorizedTransactions({ + ids: uncategorizedTransationsIdsSelected, + }) + .then(() => { + AppToaster.show({ + message: 'The selected transactions have been excluded.', + intent: Intent.SUCCESS, + }); + }) + .catch(() => { + AppToaster.show({ + message: 'Something went wrong', + intent: Intent.DANGER, + }); + }); + }; + + // Handles the unexclude categorized button click. + const handleUnexcludeUncategorizedBtnClick = () => { + unexcludeUncategorizedTransactions({ + ids: excludedTransactionsIdsSelected, + }) + .then(() => { + AppToaster.show({ + message: 'The selected transactions have been unexcluded.', + intent: Intent.SUCCESS, + }); + }) + .catch((error) => { + AppToaster.show({ + message: 'Something went wrong', + intent: Intent.DANGER, + }); + }); + }; + return ( @@ -129,6 +190,28 @@ function AccountTransactionsActionsBar({ onChange={handleTableRowSizeChange} /> + + {!isEmpty(uncategorizedTransationsIdsSelected) && ( + + {!isEmpty(entries) && ( + + )} )} diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormProvider.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormProvider.tsx index f5d0c50d3..6a33713a7 100644 --- a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormProvider.tsx +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormProvider.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import React, { createContext, useContext } from 'react'; +import React, { createContext, useContext, useState } from 'react'; import { Features } from '@/constants'; import { useFeatureCan } from '@/hooks/state'; import { @@ -71,6 +71,8 @@ function PaymentMadeFormProvider({ query, paymentMadeId, ...props }) { const isFeatureLoading = isBranchesLoading; + const [isExcessConfirmed, setIsExcessConfirmed] = useState(false); + // Provider payload. const provider = { paymentMadeId, @@ -98,6 +100,9 @@ function PaymentMadeFormProvider({ query, paymentMadeId, ...props }) { setSubmitPayload, setPaymentVendorId, + + isExcessConfirmed, + setIsExcessConfirmed, }; return ( diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/PaymentMadeExcessDialog.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/PaymentMadeExcessDialog.tsx new file mode 100644 index 000000000..c93c85a17 --- /dev/null +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/PaymentMadeExcessDialog.tsx @@ -0,0 +1,37 @@ +// @ts-nocheck +import React from 'react'; +import { Dialog, DialogSuspense } from '@/components'; +import withDialogRedux from '@/components/DialogReduxConnect'; +import { compose } from '@/utils'; + +const ExcessPaymentDialogContent = React.lazy(() => + import('./PaymentMadeExcessDialogContent').then((module) => ({ + default: module.ExcessPaymentDialogContent, + })), +); + +/** + * Exess payment dialog of the payment made form. + */ +function ExcessPaymentDialogRoot({ dialogName, isOpen }) { + return ( + + + + + + ); +} + +export const ExcessPaymentDialog = compose(withDialogRedux())( + ExcessPaymentDialogRoot, +); + +ExcessPaymentDialog.displayName = 'ExcessPaymentDialog'; diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/PaymentMadeExcessDialogContent.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/PaymentMadeExcessDialogContent.tsx new file mode 100644 index 000000000..c57f67131 --- /dev/null +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/PaymentMadeExcessDialogContent.tsx @@ -0,0 +1,93 @@ +// @ts-nocheck +import * as R from 'ramda'; +import React from 'react'; +import { Button, Classes, Intent } from '@blueprintjs/core'; +import { Form, Formik, FormikHelpers, useFormikContext } from 'formik'; +import { FormatNumber } from '@/components'; +import { usePaymentMadeFormContext } from '../../PaymentMadeFormProvider'; +import withDialogActions from '@/containers/Dialog/withDialogActions'; +import { usePaymentMadeExcessAmount } from '../../utils'; + +interface ExcessPaymentValues {} +function ExcessPaymentDialogContentRoot({ dialogName, closeDialog }) { + const { + submitForm, + values: { currency_code: currencyCode }, + } = useFormikContext(); + const { setIsExcessConfirmed } = usePaymentMadeFormContext(); + + // Handles the form submitting. + const handleSubmit = ( + values: ExcessPaymentValues, + { setSubmitting }: FormikHelpers, + ) => { + setSubmitting(true); + setIsExcessConfirmed(true); + + return submitForm().then(() => { + setSubmitting(false); + closeDialog(dialogName); + }); + }; + // Handle close button click. + const handleCloseBtn = () => { + closeDialog(dialogName); + }; + const excessAmount = usePaymentMadeExcessAmount(); + + return ( + +
+ + } + onClose={handleCloseBtn} + /> + +
+ ); +} + +export const ExcessPaymentDialogContent = R.compose(withDialogActions)( + ExcessPaymentDialogContentRoot, +); + +interface ExcessPaymentDialogContentFormProps { + excessAmount: string | number | React.ReactNode; + onClose?: () => void; +} + +function ExcessPaymentDialogContentForm({ + excessAmount, + onClose, +}: ExcessPaymentDialogContentFormProps) { + const { submitForm, isSubmitting } = useFormikContext(); + + const handleCloseBtn = () => { + onClose && onClose(); + }; + return ( + <> +
+

+ Would you like to record the excess amount of{' '} + {excessAmount} as credit payment from the vendor. +

+
+ +
+
+ + +
+
+ + ); +} diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/index.ts b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/index.ts new file mode 100644 index 000000000..dae9903b5 --- /dev/null +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/dialogs/PaymentMadeExcessDialog/index.ts @@ -0,0 +1 @@ +export * from './PaymentMadeExcessDialog'; \ No newline at end of file diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx index fd469ce88..8b8323939 100644 --- a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx @@ -37,7 +37,7 @@ export const defaultPaymentMadeEntry = { // Default initial values of payment made. export const defaultPaymentMade = { - full_amount: '', + amount: '', vendor_id: '', payment_account_id: '', payment_date: moment(new Date()).format('YYYY-MM-DD'), @@ -53,10 +53,10 @@ export const defaultPaymentMade = { export const transformToEditForm = (paymentMade, paymentMadeEntries) => { const attachments = transformAttachmentsToForm(paymentMade); + const appliedAmount = safeSumBy(paymentMadeEntries, 'payment_amount'); return { ...transformToForm(paymentMade, defaultPaymentMade), - full_amount: safeSumBy(paymentMadeEntries, 'payment_amount'), entries: [ ...paymentMadeEntries.map((paymentMadeEntry) => ({ ...transformToForm(paymentMadeEntry, defaultPaymentMadeEntry), @@ -177,6 +177,30 @@ export const usePaymentMadeTotals = () => { }; }; +export const usePaymentmadeTotalAmount = () => { + const { + values: { amount }, + } = useFormikContext(); + + return amount; +}; + +export const usePaymentMadeAppliedAmount = () => { + const { + values: { entries }, + } = useFormikContext(); + + // Retrieves the invoice entries total. + return React.useMemo(() => sumBy(entries, 'payment_amount'), [entries]); +}; + +export const usePaymentMadeExcessAmount = () => { + const appliedAmount = usePaymentMadeAppliedAmount(); + const totalAmount = usePaymentmadeTotalAmount(); + + return Math.abs(totalAmount - appliedAmount); +}; + /** * Detarmines whether the bill has foreign customer. * @returns {boolean} @@ -191,3 +215,10 @@ export const usePaymentMadeIsForeignCustomer = () => { ); return isForeignCustomer; }; + +export const getPaymentExcessAmountFromValues = (values) => { + const appliedAmount = sumBy(values.entries, 'payment_amount'); + const totalAmount = values.amount; + + return Math.abs(totalAmount - appliedAmount); +}; diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.tsx index a0c84bacb..be69cee4d 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import React, { useMemo } from 'react'; +import React, { useMemo, useRef } from 'react'; import { sumBy, isEmpty, defaultTo } from 'lodash'; import intl from 'react-intl-universal'; import classNames from 'classnames'; @@ -21,6 +21,7 @@ import { PaymentReceiveInnerProvider } from './PaymentReceiveInnerProvider'; import withSettings from '@/containers/Settings/withSettings'; import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization'; +import withDialogActions from '@/containers/Dialog/withDialogActions'; import { EditPaymentReceiveFormSchema, @@ -36,6 +37,7 @@ import { transformFormToRequest, transformErrors, resetFormState, + getExceededAmountFromValues, } from './utils'; import { PaymentReceiveSyncIncrementSettingsToForm } from './components'; @@ -51,6 +53,9 @@ function PaymentReceiveForm({ // #withCurrentOrganization organization: { base_currency }, + + // #withDialogActions + openDialog, }) { const history = useHistory(); @@ -63,6 +68,7 @@ function PaymentReceiveForm({ submitPayload, editPaymentReceiveMutate, createPaymentReceiveMutate, + isExcessConfirmed, } = usePaymentReceiveFormContext(); // Payment receive number. @@ -94,18 +100,16 @@ function PaymentReceiveForm({ preferredDepositAccount, ], ); - // Handle form submit. const handleSubmitForm = ( values, { setSubmitting, resetForm, setFieldError }, ) => { setSubmitting(true); + const exceededAmount = getExceededAmountFromValues(values); - // Calculates the total payment amount of entries. - const totalPaymentAmount = sumBy(values.entries, 'payment_amount'); - - if (totalPaymentAmount <= 0) { + // Validates the amount should be bigger than zero. + if (values.amount <= 0) { AppToaster.show({ message: intl.get('you_cannot_make_payment_with_zero_total_amount'), intent: Intent.DANGER, @@ -113,6 +117,13 @@ function PaymentReceiveForm({ setSubmitting(false); return; } + // Show the confirm popup if the excessed amount bigger than zero and + // excess confirmation has not been confirmed yet. + if (exceededAmount > 0 && !isExcessConfirmed) { + setSubmitting(false); + openDialog('payment-received-excessed-payment'); + return; + } // Transformes the form values to request body. const form = transformFormToRequest(values); @@ -148,11 +159,11 @@ function PaymentReceiveForm({ }; if (paymentReceiveId) { - editPaymentReceiveMutate([paymentReceiveId, form]) + return editPaymentReceiveMutate([paymentReceiveId, form]) .then(onSaved) .catch(onError); } else { - createPaymentReceiveMutate(form).then(onSaved).catch(onError); + return createPaymentReceiveMutate(form).then(onSaved).catch(onError); } }; return ( @@ -202,4 +213,5 @@ export default compose( preferredDepositAccount: paymentReceiveSettings?.preferredDepositAccount, })), withCurrentOrganization(), + withDialogActions, )(PaymentReceiveForm); diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormDialogs.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormDialogs.tsx index e60b27142..76ccb72a4 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormDialogs.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormDialogs.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { useFormikContext } from 'formik'; import PaymentReceiveNumberDialog from '@/containers/Dialogs/PaymentReceiveNumberDialog'; +import { ExcessPaymentDialog } from './dialogs/ExcessPaymentDialog'; /** * Payment receive form dialogs. @@ -21,9 +22,12 @@ export default function PaymentReceiveFormDialogs() { }; return ( - + <> + + + ); } diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFootetRight.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFootetRight.tsx index d35d7c6a7..2cee6c9f7 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFootetRight.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFootetRight.tsx @@ -7,11 +7,16 @@ import { TotalLine, TotalLineBorderStyle, TotalLineTextStyle, + FormatNumber, } from '@/components'; -import { usePaymentReceiveTotals } from './utils'; +import { + usePaymentReceiveTotals, + usePaymentReceivedTotalExceededAmount, +} from './utils'; export function PaymentReceiveFormFootetRight() { const { formattedSubtotal, formattedTotal } = usePaymentReceiveTotals(); + const exceededAmount = usePaymentReceivedTotalExceededAmount(); return ( @@ -25,6 +30,11 @@ export function PaymentReceiveFormFootetRight() { value={formattedTotal} textStyle={TotalLineTextStyle.Bold} /> + } + textStyle={TotalLineTextStyle.Regular} + /> ); } diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormHeader.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormHeader.tsx index d7e44fadf..c6d08f074 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormHeader.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormHeader.tsx @@ -30,15 +30,9 @@ function PaymentReceiveFormHeader() { function PaymentReceiveFormBigTotal() { // Formik form context. const { - values: { currency_code, entries }, + values: { currency_code, amount }, } = useFormikContext(); - // Calculates the total payment amount from due amount. - const paymentFullAmount = useMemo( - () => sumBy(entries, 'payment_amount'), - [entries], - ); - return (
@@ -46,7 +40,7 @@ function PaymentReceiveFormBigTotal() {

- +

diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormProvider.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormProvider.tsx index 8c08abd3e..c6f5a4729 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormProvider.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormProvider.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import React, { createContext, useContext } from 'react'; +import React, { createContext, useContext, useState } from 'react'; import { Features } from '@/constants'; import { useFeatureCan } from '@/hooks/state'; import { DashboardInsider } from '@/components'; @@ -74,6 +74,8 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) { const { mutateAsync: editPaymentReceiveMutate } = useEditPaymentReceive(); const { mutateAsync: createPaymentReceiveMutate } = useCreatePaymentReceive(); + const [isExcessConfirmed, setIsExcessConfirmed] = useState(false); + // Provider payload. const provider = { paymentReceiveId, @@ -97,6 +99,9 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) { editPaymentReceiveMutate, createPaymentReceiveMutate, + + isExcessConfirmed, + setIsExcessConfirmed, }; return ( diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.tsx index 9ed1e5503..98b9fe4e2 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.tsx @@ -11,7 +11,7 @@ import { Button, } from '@blueprintjs/core'; import { DateInput } from '@blueprintjs/datetime'; -import { toSafeInteger } from 'lodash'; +import { isEmpty, toSafeInteger } from 'lodash'; import { FastField, Field, useFormikContext, ErrorMessage } from 'formik'; import { @@ -124,11 +124,11 @@ export default function PaymentReceiveHeaderFields() { {/* ------------ Full amount ------------ */} - + {({ form: { setFieldValue, - values: { currency_code }, + values: { currency_code, entries }, }, field: { value, onChange }, meta: { error, touched }, @@ -146,21 +146,23 @@ export default function PaymentReceiveHeaderFields() { { - setFieldValue('full_amount', value); + setFieldValue('amount', value); }} onBlurValue={onFullAmountBlur} /> - + {!isEmpty(entries) && ( + + )} )} diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/ExcessPaymentDialog.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/ExcessPaymentDialog.tsx new file mode 100644 index 000000000..44e660e76 --- /dev/null +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/ExcessPaymentDialog.tsx @@ -0,0 +1,37 @@ +// @ts-nocheck +import React from 'react'; +import { Dialog, DialogSuspense } from '@/components'; +import withDialogRedux from '@/components/DialogReduxConnect'; +import { compose } from '@/utils'; + +const ExcessPaymentDialogContent = React.lazy(() => + import('./ExcessPaymentDialogContent').then((module) => ({ + default: module.ExcessPaymentDialogContent, + })), +); + +/** + * Excess payment dialog of the payment received form. + */ +function ExcessPaymentDialogRoot({ dialogName, isOpen }) { + return ( + + + + + + ); +} + +export const ExcessPaymentDialog = compose(withDialogRedux())( + ExcessPaymentDialogRoot, +); + +ExcessPaymentDialog.displayName = 'ExcessPaymentDialog'; diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/ExcessPaymentDialogContent.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/ExcessPaymentDialogContent.tsx new file mode 100644 index 000000000..868a75bdf --- /dev/null +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/ExcessPaymentDialogContent.tsx @@ -0,0 +1,86 @@ +// @ts-nocheck +import * as Yup from 'yup'; +import * as R from 'ramda'; +import { Button, Classes, Intent } from '@blueprintjs/core'; +import { Form, Formik, FormikHelpers, useFormikContext } from 'formik'; +import { FormatNumber } from '@/components'; +import { usePaymentReceiveFormContext } from '../../PaymentReceiveFormProvider'; +import withDialogActions from '@/containers/Dialog/withDialogActions'; +import { usePaymentReceivedTotalExceededAmount } from '../../utils'; + +interface ExcessPaymentValues {} + +export function ExcessPaymentDialogContentRoot({ dialogName, closeDialog }) { + const { + submitForm, + values: { currency_code: currencyCode }, + } = useFormikContext(); + const { setIsExcessConfirmed } = usePaymentReceiveFormContext(); + const exceededAmount = usePaymentReceivedTotalExceededAmount(); + + const handleSubmit = ( + values: ExcessPaymentValues, + { setSubmitting }: FormikHelpers, + ) => { + setSubmitting(true); + setIsExcessConfirmed(true); + + submitForm().then(() => { + closeDialog(dialogName); + setSubmitting(false); + }); + }; + const handleClose = () => { + closeDialog(dialogName); + }; + + return ( + +
+ + } + onClose={handleClose} + /> + +
+ ); +} + +export const ExcessPaymentDialogContent = R.compose(withDialogActions)( + ExcessPaymentDialogContentRoot, +); + +function ExcessPaymentDialogContentForm({ onClose, exceededAmount }) { + const { submitForm, isSubmitting } = useFormikContext(); + + const handleCloseBtn = () => { + onClose && onClose(); + }; + + return ( + <> +
+

+ Would you like to record the excess amount of{' '} + {exceededAmount} as credit payment from the customer. +

+
+ +
+
+ + +
+
+ + ); +} diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/index.ts b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/index.ts new file mode 100644 index 000000000..9be100852 --- /dev/null +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/dialogs/ExcessPaymentDialog/index.ts @@ -0,0 +1 @@ +export * from './ExcessPaymentDialog'; \ No newline at end of file diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx index 71f75280a..3be7c0ea4 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx @@ -42,12 +42,12 @@ export const defaultPaymentReceive = { // Holds the payment number that entered manually only. payment_receive_no_manually: '', statement: '', - full_amount: '', + amount: '', currency_code: '', branch_id: '', exchange_rate: 1, entries: [], - attachments: [] + attachments: [], }; export const defaultRequestPaymentEntry = { @@ -249,6 +249,30 @@ export const usePaymentReceiveTotals = () => { }; }; +export const usePaymentReceivedTotalAppliedAmount = () => { + const { + values: { entries }, + } = useFormikContext(); + + // Retrieves the invoice entries total. + return React.useMemo(() => sumBy(entries, 'payment_amount'), [entries]); +}; + +export const usePaymentReceivedTotalAmount = () => { + const { + values: { amount }, + } = useFormikContext(); + + return amount; +}; + +export const usePaymentReceivedTotalExceededAmount = () => { + const totalAmount = usePaymentReceivedTotalAmount(); + const totalApplied = usePaymentReceivedTotalAppliedAmount(); + + return Math.abs(totalAmount - totalApplied); +}; + /** * Detarmines whether the payment has foreign customer. * @returns {boolean} @@ -273,3 +297,10 @@ export const resetFormState = ({ initialValues, values, resetForm }) => { }, }); }; + +export const getExceededAmountFromValues = (values) => { + const totalApplied = sumBy(values.entries, 'payment_amount'); + const totalAmount = values.amount; + + return totalAmount - totalApplied; +}; From 9e6500ac79af59e09f11d2199ef0cd07089a83c6 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Thu, 25 Jul 2024 19:17:54 +0200 Subject: [PATCH 5/8] feat: remove the views tabs bar from all tables --- .../Accounting/JournalsLanding/ManualJournalsList.tsx | 2 -- packages/webapp/src/containers/Accounts/AccountsChart.tsx | 6 ++---- .../containers/Customers/CustomersLanding/CustomersList.tsx | 2 -- .../containers/Expenses/ExpensesLanding/ExpensesList.tsx | 2 -- packages/webapp/src/containers/Items/ItemsList.tsx | 2 -- .../containers/Purchases/Bills/BillsLanding/BillsList.tsx | 2 -- .../CreditNotesLanding/VendorsCreditNotesList.tsx | 2 -- .../PaymentMades/PaymentsLanding/PaymentMadeList.tsx | 2 -- .../CreditNotes/CreditNotesLanding/CreditNotesList.tsx | 3 +-- .../Sales/Estimates/EstimatesLanding/EstimatesList.tsx | 4 +--- .../Sales/Invoices/InvoicesLanding/InvoicesList.tsx | 2 -- .../PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx | 1 - .../src/containers/Vendors/VendorsLanding/VendorsList.tsx | 2 -- .../WarehouseTransfersLanding/WarehouseTransfersList.tsx | 3 +-- 14 files changed, 5 insertions(+), 30 deletions(-) diff --git a/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalsList.tsx b/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalsList.tsx index 749ac981f..cd0135010 100644 --- a/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalsList.tsx +++ b/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalsList.tsx @@ -7,7 +7,6 @@ import { DashboardPageContent } from '@/components'; import { transformTableStateToQuery, compose } from '@/utils'; import { ManualJournalsListProvider } from './ManualJournalsListProvider'; -import ManualJournalsViewTabs from './ManualJournalsViewTabs'; import ManualJournalsDataTable from './ManualJournalsDataTable'; import ManualJournalsActionsBar from './ManualJournalActionsBar'; import withManualJournals from './withManualJournals'; @@ -29,7 +28,6 @@ function ManualJournalsTable({ - diff --git a/packages/webapp/src/containers/Accounts/AccountsChart.tsx b/packages/webapp/src/containers/Accounts/AccountsChart.tsx index 271e3260d..4be0c9c6c 100644 --- a/packages/webapp/src/containers/Accounts/AccountsChart.tsx +++ b/packages/webapp/src/containers/Accounts/AccountsChart.tsx @@ -2,15 +2,15 @@ import React, { useEffect } from 'react'; import '@/style/pages/Accounts/List.scss'; -import { DashboardPageContent, DashboardContentTable } from '@/components'; +import { DashboardPageContent, DashboardContentTable } from '@/components'; import { AccountsChartProvider } from './AccountsChartProvider'; -import AccountsViewsTabs from './AccountsViewsTabs'; import AccountsActionsBar from './AccountsActionsBar'; import AccountsDataTable from './AccountsDataTable'; import withAccounts from '@/containers/Accounts/withAccounts'; import withAccountsTableActions from './withAccountsTableActions'; + import { transformAccountsStateToQuery } from './utils'; import { compose } from '@/utils'; @@ -41,8 +41,6 @@ function AccountsChart({ - - diff --git a/packages/webapp/src/containers/Customers/CustomersLanding/CustomersList.tsx b/packages/webapp/src/containers/Customers/CustomersLanding/CustomersList.tsx index cdf293905..3f9cddef2 100644 --- a/packages/webapp/src/containers/Customers/CustomersLanding/CustomersList.tsx +++ b/packages/webapp/src/containers/Customers/CustomersLanding/CustomersList.tsx @@ -6,7 +6,6 @@ import '@/style/pages/Customers/List.scss'; import { DashboardPageContent } from '@/components'; import CustomersActionsBar from './CustomersActionsBar'; -import CustomersViewsTabs from './CustomersViewsTabs'; import CustomersTable from './CustomersTable'; import { CustomersListProvider } from './CustomersListProvider'; @@ -42,7 +41,6 @@ function CustomersList({ - diff --git a/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpensesList.tsx b/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpensesList.tsx index 65e9e69fa..c92ca6cdb 100644 --- a/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpensesList.tsx +++ b/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpensesList.tsx @@ -6,7 +6,6 @@ import '@/style/pages/Expense/List.scss'; import { DashboardPageContent } from '@/components'; import ExpenseActionsBar from './ExpenseActionsBar'; -import ExpenseViewTabs from './ExpenseViewTabs'; import ExpenseDataTable from './ExpenseDataTable'; import withExpenses from './withExpenses'; @@ -42,7 +41,6 @@ function ExpensesList({ - diff --git a/packages/webapp/src/containers/Items/ItemsList.tsx b/packages/webapp/src/containers/Items/ItemsList.tsx index 017a5302c..de6c10ea1 100644 --- a/packages/webapp/src/containers/Items/ItemsList.tsx +++ b/packages/webapp/src/containers/Items/ItemsList.tsx @@ -8,7 +8,6 @@ import { DashboardPageContent } from '@/components'; import { ItemsListProvider } from './ItemsListProvider'; import ItemsActionsBar from './ItemsActionsBar'; -import ItemsViewsTabs from './ItemsViewsTabs'; import ItemsDataTable from './ItemsDataTable'; import withItems from './withItems'; @@ -41,7 +40,6 @@ function ItemsList({ - diff --git a/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsList.tsx b/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsList.tsx index 7e6bb795d..5afd9ffa3 100644 --- a/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsList.tsx +++ b/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsList.tsx @@ -7,7 +7,6 @@ import '@/style/pages/Bills/List.scss'; import { BillsListProvider } from './BillsListProvider'; import BillsActionsBar from './BillsActionsBar'; -import BillsViewsTabs from './BillsViewsTabs'; import BillsTable from './BillsTable'; import withBills from './withBills'; @@ -42,7 +41,6 @@ function BillsList({ - diff --git a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.tsx b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.tsx index 02f3345b5..0ac4158fe 100644 --- a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.tsx +++ b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNotesList.tsx @@ -5,7 +5,6 @@ import '@/style/pages/VendorsCreditNote/List.scss'; import { DashboardPageContent } from '@/components'; import VendorsCreditNoteActionsBar from './VendorsCreditNoteActionsBar'; -import VendorsCreditNoteViewTabs from './VendorsCreditNoteViewTabs'; import VendorsCreditNoteDataTable from './VendorsCreditNoteDataTable'; import withVendorsCreditNotes from './withVendorsCreditNotes'; @@ -37,7 +36,6 @@ function VendorsCreditNotesList({ > - diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeList.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeList.tsx index f2fa51028..45427c1cc 100644 --- a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeList.tsx +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeList.tsx @@ -7,7 +7,6 @@ import { DashboardPageContent } from '@/components'; import { PaymentMadesListProvider } from './PaymentMadesListProvider'; import PaymentMadeActionsBar from './PaymentMadeActionsBar'; import PaymentMadesTable from './PaymentMadesTable'; -import PaymentMadeViewTabs from './PaymentMadeViewTabs'; import withPaymentMades from './withPaymentMade'; import withPaymentMadeActions from './withPaymentMadeActions'; @@ -41,7 +40,6 @@ function PaymentMadeList({ - diff --git a/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.tsx b/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.tsx index 13873aacc..360c5a6a0 100644 --- a/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.tsx +++ b/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesList.tsx @@ -5,7 +5,6 @@ import '@/style/pages/CreditNote/List.scss'; import { DashboardPageContent } from '@/components'; import CreditNotesActionsBar from './CreditNotesActionsBar'; -import CreditNotesViewTabs from './CreditNotesViewTabs'; import CreditNotesDataTable from './CreditNotesDataTable'; import withCreditNotes from './withCreditNotes'; @@ -36,8 +35,8 @@ function CreditNotesList({ tableStateChanged={creditNoteTableStateChanged} > + - diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesList.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesList.tsx index 39c33cfc4..866871f4b 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesList.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesList.tsx @@ -1,11 +1,10 @@ // @ts-nocheck import React from 'react'; -import { DashboardContentTable, DashboardPageContent } from '@/components'; +import { DashboardPageContent } from '@/components'; import '@/style/pages/SaleEstimate/List.scss'; import EstimatesActionsBar from './EstimatesActionsBar'; -import EstimatesViewTabs from './EstimatesViewTabs'; import EstimatesDataTable from './EstimatesDataTable'; import withEstimates from './withEstimates'; @@ -41,7 +40,6 @@ function EstimatesList({ - diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesList.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesList.tsx index dc4577d0d..e846dc86a 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesList.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesList.tsx @@ -6,7 +6,6 @@ import '@/style/pages/SaleInvoice/List.scss'; import { DashboardPageContent } from '@/components'; import { InvoicesListProvider } from './InvoicesListProvider'; -import InvoiceViewTabs from './InvoiceViewTabs'; import InvoicesDataTable from './InvoicesDataTable'; import InvoicesActionsBar from './InvoicesActionsBar'; @@ -43,7 +42,6 @@ function InvoicesList({ - diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx index f2d8b2bb3..66a7b59d6 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx @@ -41,7 +41,6 @@ function PaymentReceiveList({ - diff --git a/packages/webapp/src/containers/Vendors/VendorsLanding/VendorsList.tsx b/packages/webapp/src/containers/Vendors/VendorsLanding/VendorsList.tsx index c558f6024..edc173dc0 100644 --- a/packages/webapp/src/containers/Vendors/VendorsLanding/VendorsList.tsx +++ b/packages/webapp/src/containers/Vendors/VendorsLanding/VendorsList.tsx @@ -7,7 +7,6 @@ import { DashboardPageContent } from '@/components'; import { VendorsListProvider } from './VendorsListProvider'; import VendorActionsBar from './VendorActionsBar'; -import VendorViewsTabs from './VendorViewsTabs'; import VendorsTable from './VendorsTable'; import withVendors from './withVendors'; @@ -42,7 +41,6 @@ function VendorsList({ - diff --git a/packages/webapp/src/containers/WarehouseTransfers/WarehouseTransfersLanding/WarehouseTransfersList.tsx b/packages/webapp/src/containers/WarehouseTransfers/WarehouseTransfersLanding/WarehouseTransfersList.tsx index 83a4c8935..c57fa2762 100644 --- a/packages/webapp/src/containers/WarehouseTransfers/WarehouseTransfersLanding/WarehouseTransfersList.tsx +++ b/packages/webapp/src/containers/WarehouseTransfers/WarehouseTransfersLanding/WarehouseTransfersList.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { DashboardPageContent } from '@/components'; import WarehouseTransfersActionsBar from './WarehouseTransfersActionsBar'; -import WarehouseTransfersViewTabs from './WarehouseTransfersViewTabs'; import WarehouseTransfersDataTable from './WarehouseTransfersDataTable'; import withWarehouseTransfers from './withWarehouseTransfers'; import withWarehouseTransfersActions from './withWarehouseTransfersActions'; @@ -33,8 +32,8 @@ function WarehouseTransfersList({ tableStateChanged={warehouseTransferTableStateChanged} > + - From 0a7b522b8751ffe104183f6a04e8eeb86db104ac Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Thu, 25 Jul 2024 19:21:16 +0200 Subject: [PATCH 6/8] chore: remove unused import --- .../PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx index 66a7b59d6..38a04e170 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceivesList.tsx @@ -5,7 +5,6 @@ import '@/style/pages/PaymentReceive/List.scss'; import { DashboardPageContent } from '@/components'; import { PaymentReceivesListProvider } from './PaymentReceiptsListProvider'; -import PaymentReceiveViewTabs from './PaymentReceiveViewTabs'; import PaymentReceivesTable from './PaymentReceivesTable'; import PaymentReceiveActionsBar from './PaymentReceiveActionsBar'; From 14d5e82b4aa4394d877435898c7ae69310e2d66f Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Mon, 29 Jul 2024 12:00:34 +0200 Subject: [PATCH 7/8] fix: style of database checkbox --- .../src/style/components/DataTable/DataTable.scss | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/webapp/src/style/components/DataTable/DataTable.scss b/packages/webapp/src/style/components/DataTable/DataTable.scss index cf4018489..1c1b138cd 100644 --- a/packages/webapp/src/style/components/DataTable/DataTable.scss +++ b/packages/webapp/src/style/components/DataTable/DataTable.scss @@ -124,22 +124,18 @@ } } - .bp4-control.bp4-checkbox .bp4-control-indicator { + .bp4-control.bp4-checkbox .bp4-control-indicator { cursor: auto; &, - &:hover { + &::before { height: 15px; width: 15px; } } - .bp4-control.bp4-checkbox { - - input:checked~.bp4-control-indicator, - input:indeterminate~.bp4-control-indicator { - border-color: #0052ff; - } + .bp4-control.bp4-checkbox input:not(:checked):not(:indeterminate) ~ .bp4-control-indicator{ + box-shadow: inset 0 0 0 1px #C5CBD3; } .skeleton { From 4345623ea9c512b0210f22d0682b5c04ce1a77dd Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Mon, 29 Jul 2024 13:00:50 +0200 Subject: [PATCH 8/8] feat: document functions --- .../Banking/Exclude/ExcludeBankTransactions.ts | 5 +++-- .../Exclude/UnexcludeBankTransactions.ts | 2 +- .../AccountTransactionsActionsBar.tsx | 8 +++----- .../containers/CashFlow/withBankingActions.ts | 16 ++++++++++++++++ .../src/store/banking/banking.reducer.ts | 18 ++++++++++++++++++ .../src/style/pages/Dashboard/Dashboard.scss | 6 +++++- 6 files changed, 46 insertions(+), 9 deletions(-) diff --git a/packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts b/packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts index abf6bd434..65d65a7c1 100644 --- a/packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts +++ b/packages/server/src/services/Banking/Exclude/ExcludeBankTransactions.ts @@ -1,7 +1,7 @@ import { Inject, Service } from 'typedi'; -import { ExcludeBankTransaction } from './ExcludeBankTransaction'; import PromisePool from '@supercharge/promise-pool'; import { castArray } from 'lodash'; +import { ExcludeBankTransaction } from './ExcludeBankTransaction'; @Service() export class ExcludeBankTransactions { @@ -12,6 +12,7 @@ export class ExcludeBankTransactions { * Exclude bank transactions in bulk. * @param {number} tenantId * @param {number} bankTransactionIds + * @returns {Promise} */ public async excludeBankTransactions( tenantId: number, @@ -21,7 +22,7 @@ export class ExcludeBankTransactions { await PromisePool.withConcurrency(1) .for(_bankTransactionIds) - .process(async (bankTransactionId: number) => { + .process((bankTransactionId: number) => { return this.excludeBankTransaction.excludeBankTransaction( tenantId, bankTransactionId diff --git a/packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts b/packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts index 840eb6259..846ea1fd8 100644 --- a/packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts +++ b/packages/server/src/services/Banking/Exclude/UnexcludeBankTransactions.ts @@ -21,7 +21,7 @@ export class UnexcludeBankTransactions { await PromisePool.withConcurrency(1) .for(_bankTransactionIds) - .process(async (bankTransactionId: number) => { + .process((bankTransactionId: number) => { return this.unexcludeBankTransaction.unexcludeBankTransaction( tenantId, bankTransactionId diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx index 7ca9abc37..53ef5a786 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsActionsBar.tsx @@ -39,7 +39,6 @@ import { withBanking } from '../withBanking'; import { isEmpty } from 'lodash'; import { useExcludeUncategorizedTransactions, - useUnexcludeUncategorizedTransaction, useUnexcludeUncategorizedTransactions, } from '@/hooks/query/bank-rules'; @@ -136,7 +135,7 @@ function AccountTransactionsActionsBar({ }) .then(() => { AppToaster.show({ - message: 'The selected transactions have been unexcluded.', + message: 'The selected excluded transactions have been unexcluded.', intent: Intent.SUCCESS, }); }) @@ -198,10 +197,9 @@ function AccountTransactionsActionsBar({ onClick={handleExcludeUncategorizedBtnClick} className={Classes.MINIMAL} intent={Intent.DANGER} - disable={isExcludingLoading} + disabled={isExcludingLoading} /> )} - {!isEmpty(excludedTransactionsIdsSelected) && (