diff --git a/banking/src/components/features/BankReconciliation/BankBalance.tsx b/banking/src/components/features/BankReconciliation/BankBalance.tsx index 7a7b0a4925c..a46ce362140 100644 --- a/banking/src/components/features/BankReconciliation/BankBalance.tsx +++ b/banking/src/components/features/BankReconciliation/BankBalance.tsx @@ -53,7 +53,7 @@ const OpeningBalance = () => { return {_("Opening Balance")} - {isLoading ? : {formatCurrency(flt(data?.message, 2), bankAccount?.account_currency ?? getCompanyCurrency(bankAccount?.company ?? ''))}} + {isLoading ? : {formatCurrency(flt(data?.message, 2), bankAccount?.account_currency ?? getCompanyCurrency(bankAccount?.company ?? ''))}} } @@ -86,7 +86,7 @@ const ClosingBalance = () => { - {isLoading ? : {formatCurrency(flt(data?.message, 2), bankAccount?.account_currency ?? getCompanyCurrency(bankAccount?.company ?? ''))}} + {isLoading ? : {formatCurrency(flt(data?.message, 2), bankAccount?.account_currency ?? getCompanyCurrency(bankAccount?.company ?? ''))}} ) } @@ -104,7 +104,7 @@ const Difference = () => { return {_("Difference")} - {isLoading ? : + {isLoading ? : {formatCurrency(difference, bankAccount?.account_currency ?? getCompanyCurrency(bankAccount?.company ?? '')) }} @@ -175,7 +175,7 @@ const ClosingBalanceAsPerStatement = () => {
- {isLoading ? : {formatCurrency(flt(data?.message?.balance, 2), bankAccount?.account_currency ?? getCompanyCurrency(bankAccount?.company ?? ''))}} + {isLoading ? : {formatCurrency(flt(data?.message?.balance, 2), bankAccount?.account_currency ?? getCompanyCurrency(bankAccount?.company ?? ''))}}
diff --git a/banking/src/components/features/BankReconciliation/BankPicker.tsx b/banking/src/components/features/BankReconciliation/BankPicker.tsx index 9150103fd32..47b087bfa81 100644 --- a/banking/src/components/features/BankReconciliation/BankPicker.tsx +++ b/banking/src/components/features/BankReconciliation/BankPicker.tsx @@ -1,4 +1,4 @@ -import { useAtom, useSetAtom } from "jotai" +import { useAtom } from "jotai" import { SelectedBank, selectedBankAccountAtom } from "./bankRecAtoms" import { useCallback } from "react" import { useGetBankAccounts, useGetUnreconciledTransactions } from "./utils" @@ -16,9 +16,16 @@ import { useCurrentCompany } from "@/hooks/useCurrentCompany" const BankPicker = ({ className }: { className?: string }) => { - const setSelectedBank = useSetAtom(selectedBankAccountAtom) + const [selectedBank, setSelectedBank] = useAtom(selectedBankAccountAtom) const onLoadingSuccess = useCallback((data?: SelectedBank[]) => { + // If the bank is already selected, then don't set it again + if (selectedBank) { + // Check if selected bank is in the data + if (data?.some((bank: SelectedBank) => bank.name === selectedBank.name)) { + return + } + } if (!data) return if (data.length === 1) { setSelectedBank(data[0]) @@ -26,9 +33,12 @@ const BankPicker = ({ className }: { className?: string }) => { const defaultBank = data.find((bank: SelectedBank) => bank.is_default) if (defaultBank) { setSelectedBank(defaultBank) + } else { + // Select the first available bank account + setSelectedBank(data[0]) } } - }, [setSelectedBank]) + }, [setSelectedBank, selectedBank]) const selectedCompany = useCurrentCompany() diff --git a/banking/src/components/features/BankReconciliation/BankTransactionList.tsx b/banking/src/components/features/BankReconciliation/BankTransactionList.tsx index 05e35f0f289..c37165349fe 100644 --- a/banking/src/components/features/BankReconciliation/BankTransactionList.tsx +++ b/banking/src/components/features/BankReconciliation/BankTransactionList.tsx @@ -21,7 +21,7 @@ import { useDebounceValue } from "usehooks-ts" import type { ColumnDef } from "@tanstack/react-table" import { useCallback, useMemo, useState } from "react" import { Link } from "react-router" -import { Empty, EmptyTitle, EmptyHeader, EmptyMedia, EmptyDescription } from "@/components/ui/empty" +import { Empty, EmptyTitle, EmptyHeader, EmptyMedia, EmptyDescription, EmptyContent } from "@/components/ui/empty" import { InputGroup, InputGroupAddon } from "@/components/ui/input-group" const BankTransactions = () => { @@ -262,7 +262,7 @@ const BankTransactionListView = () => { {error && } - {data && data.message.length > 0 && { typeFilter={typeFilter} status={status} setStatus={setStatus} - />} - - {data && data.message.length > 0 ? ( - row.name} - maxHeight="calc(100vh - 200px)" - scrollAreaClassName="min-h-[calc(100vh-200px)]" - emptyState={ - - - - - {_("No bank transactions found")} - {_("There are no transactions in the system for the selected bank account and dates that match the filters.")} - - } - /> - ) : null} - + /> + row.name} + maxHeight="calc(100vh - 200px)" + scrollAreaClassName="min-h-[calc(100vh-200px)]" + emptyState={ + + + + + {_("No bank transactions found")} + {_("There are no transactions in the system for the selected bank account and dates that match the filters.")} + + {data && data.message.length === 0 ? + + : null} + } + /> } diff --git a/banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx b/banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx index 006668ac50d..32eeb672fcd 100644 --- a/banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx +++ b/banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx @@ -298,7 +298,7 @@ const UnreconciledTransactionItem = ({ transaction }: { transaction: Unreconcile tabIndex={0} onClick={handleSelectTransaction}>
-
+
{formatDate(transaction.date)} {transaction.transaction_type && @@ -314,7 +314,7 @@ const UnreconciledTransactionItem = ({ transaction }: { transaction: Unreconcile title={_("Matched by rule")}> {transaction.matched_transaction_rule}}
- {transaction.description} + {transaction.description}
{isWithdrawal ? : } diff --git a/banking/src/components/features/BankReconciliation/bankRecAtoms.ts b/banking/src/components/features/BankReconciliation/bankRecAtoms.ts index 4f6e51e51b1..5bb1c84ae82 100644 --- a/banking/src/components/features/BankReconciliation/bankRecAtoms.ts +++ b/banking/src/components/features/BankReconciliation/bankRecAtoms.ts @@ -15,7 +15,9 @@ export interface SelectedBank extends Pick(null) +export const selectedBankAccountAtom = atomWithStorage('bank-rec-selected-bank', null, undefined, { + getOnInit: true +}) export const bankRecDateAtom = atomWithStorage<{ fromDate: string, toDate: string }>("bank-rec-date", { fromDate: getDatesForTimePeriod('This Month').fromDate, diff --git a/banking/src/components/features/BankReconciliation/logos.ts b/banking/src/components/features/BankReconciliation/logos.ts index 8212b72c33f..a89c59ee6fc 100644 --- a/banking/src/components/features/BankReconciliation/logos.ts +++ b/banking/src/components/features/BankReconciliation/logos.ts @@ -393,5 +393,18 @@ export const BANK_LOGOS: { keywords: string[], logo: string, locale?: string[], logo: "Prime_Bank.png", locale: ['Kenya'], logoClassName: 'max-w-28' + }, + { + keywords: ["Stripe"], + logo: "Stripe.svg", + locale: ['Global'], + logoClassName: 'h-6', + darkModeInvert: true, + }, + { + keywords: ["PayPal"], + logo: "PayPal.png", + locale: ['Global'], + logoClassName: 'h-6', } ] \ No newline at end of file diff --git a/banking/src/components/ui/file-dropzone.tsx b/banking/src/components/ui/file-dropzone.tsx index ab0c6465c62..5e9cc41e631 100644 --- a/banking/src/components/ui/file-dropzone.tsx +++ b/banking/src/components/ui/file-dropzone.tsx @@ -31,7 +31,7 @@ export const FileDropzone = ({ files, setFiles, accept, multiple = true, onDrop, }, [setFiles, onDrop, multiple, onUpdate]) const { getRootProps, getInputProps } = useDropzone({ onDrop: onFileDrop, accept, multiple }) return ( -
+
{files.length === 0 ?

{multiple ? _("Drop some files here, or click to select files") : _("Drop a file here, or click to select a file")}

: null}
diff --git a/banking/src/components/ui/list-view.tsx b/banking/src/components/ui/list-view.tsx index f2d5759d5aa..ddd0c0e7020 100644 --- a/banking/src/components/ui/list-view.tsx +++ b/banking/src/components/ui/list-view.tsx @@ -382,7 +382,7 @@ function ListViewInner({
({ ({ header.getResizeHandler()(e) }} onTouchStart={header.getResizeHandler()} - className="absolute top-0 ltr:right-0 rtl:left-0 z-10 h-full w-2 max-w-[12px] cursor-col-resize touch-none select-none bg-transparent" + className="absolute top-0 ltr:-right-2 rtl:-left-2 z-10 h-full w-2 max-w-[12px] cursor-col-resize touch-none select-none bg-transparent" /> ) : null} diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index 0310ac0877a..e1fd656b088 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -12,7 +12,6 @@ from frappe.contacts.address_and_contact import ( ) from frappe.model.document import Document from frappe.utils import comma_and, get_link_to_form -from pypika import Order class BankAccount(Document): @@ -139,38 +138,35 @@ def get_list(company: str, show_disabled: bool = False): @return: A list of bank accounts """ - frappe.has_permission("Bank Account", ptype="read", throw=True) + filters = {"is_company_account": 1, "company": company} + if not show_disabled: + filters["disabled"] = 0 - bank_account = frappe.qb.DocType("Bank Account") - account = frappe.qb.DocType("Account") - - query = ( - frappe.qb.from_(bank_account) - .join(account) - .on(bank_account.account == account.name) - .select( - bank_account.name, - account.account_currency, - bank_account.account, - bank_account.company, - bank_account.account_name, - bank_account.is_default, - bank_account.bank, - bank_account.account_type, - bank_account.account_subtype, - bank_account.bank_account_no, - bank_account.last_integration_date, - bank_account.is_credit_card, - ) - .where(bank_account.is_company_account == 1) - .where(bank_account.company == company) - .orderby(bank_account.is_default, order=Order.desc) + bank_accounts = frappe.get_list( + "Bank Account", + filters=filters, + order_by="is_default desc", + fields=[ + "name", + "account", + "company", + "account_name", + "is_default", + "bank", + "account_type", + "account_subtype", + "bank_account_no", + "last_integration_date", + "is_credit_card", + ], ) - if not show_disabled: - query = query.where(bank_account.disabled == 0) + for bank_account in bank_accounts: + bank_account.account_currency = frappe.get_cached_value( + "Account", bank_account.account, "account_currency" + ) - return query.run(as_dict=True) + return bank_accounts @frappe.whitelist(methods=["GET"]) diff --git a/erpnext/public/images/bank-logos/PayPal.png b/erpnext/public/images/bank-logos/PayPal.png new file mode 100644 index 00000000000..601158caa4a Binary files /dev/null and b/erpnext/public/images/bank-logos/PayPal.png differ diff --git a/erpnext/public/images/bank-logos/Stripe.svg b/erpnext/public/images/bank-logos/Stripe.svg new file mode 100644 index 00000000000..f421bbcfe78 --- /dev/null +++ b/erpnext/public/images/bank-logos/Stripe.svg @@ -0,0 +1,9 @@ + + + + + + + + +