import _ from '@/lib/translate' import { GetStatementDetailsResponse } from '../import_utils' import { flt, formatCurrency } from '@/lib/numbers' import { formatDate } from '@/lib/date' import { bankRecDateAtom } from '../../BankReconciliation/bankRecAtoms' import { AlertCircleIcon, ChevronLeftIcon, ChevronRightIcon, ExternalLinkIcon, InfoIcon, Loader2Icon } from 'lucide-react' import { H2, H3, Paragraph } from '@/components/ui/typography' import { FileTypeIcon } from '@/components/ui/file-dropzone' import { getFileExtension } from '@/lib/file' import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Separator } from '@/components/ui/separator' import { Button } from '@/components/ui/button' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' import { useFrappeEventListener, useFrappePostCall } from 'frappe-react-sdk' import { toast } from 'sonner' import ErrorBanner from '@/components/ui/error-banner' import { Link, useNavigate } from 'react-router-dom' import { useMemo, useState } from 'react' import { Progress } from '@/components/ui/progress' import { useSetAtom } from 'jotai' import { useDirection } from '@/components/ui/direction' import BankLogo from '@/components/common/BankLogo' import { useGetBankAccounts } from '../../BankReconciliation/utils' import { BankStatementImportLog } from '@/types/Accounts/BankStatementImportLog' import { Badge } from '@/components/ui/badge' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' const parseDateFormat = (dateFormat: string) => { const charMap = { "%d": "DD", "%m": "MM", "%Y": "YYYY", "%y": "YY", "%b": "MMM", "%B": "MMMM", } let label = dateFormat Object.keys(charMap).forEach((char) => { label = label.replace(char, charMap[char as keyof typeof charMap]) }) return dateFormat } type Props = { data: GetStatementDetailsResponse, } const StatementDetails = ({ data }: Props) => { const dateFormat = parseDateFormat(data.date_format) const { call, loading, error } = useFrappePostCall<{ docs: BankStatementImportLog[] }>('run_doc_method') const navigate = useNavigate() const setDates = useSetAtom(bankRecDateAtom) const direction = useDirection() const onImport = () => { call({ docs: data.doc, method: 'insert_transactions' }).then((response) => { const doc = response.docs ? response.docs[0] : undefined if (doc && doc.start_date && doc.end_date) { setDates({ fromDate: doc.start_date, toDate: doc.end_date, }) } toast.success(_("Bank statement imported.")) navigate(`/`) }).catch(() => { toast.error(_("There was an error while importing the bank statement.")) }) } const [progress, setProgress] = useState(0) useFrappeEventListener("bank-rec-statement-import-progress", (event) => { setProgress(event.progress) }) const file_name = data.doc.file.split("/").pop() ?? "" const { banks } = useGetBankAccounts() const bank = useMemo(() => { return banks?.find((bank) => bank.name === data.doc.bank_account) }, [data.doc.bank_account, banks]) return (
{data.doc.status === 'Completed' ? {_("Completed")} : }

{_("Statement Details")}

{_("We've auto-detected the details of the statement file.")}
{_("Please review the details below and click the 'Import' button to proceed.")}
{progress > 0 &&
{_("Importing {0} transactions", [progress.toString()])}
} {error && } {_("Bank Account")}
{bank?.account_name} {bank?.account}
{_("Statement File")}
{file_name}
{_("Transaction Dates")} {_("{0} to {1}", [formatDate(data.doc.start_date, "Do MMMM YYYY"), formatDate(data.doc.end_date, "Do MMMM YYYY")])} {_("Number of Transactions")} {data.doc.number_of_transactions} {_("Total Debits")} {formatCurrency(flt(data.doc.total_debits, 2), data.currency)} ({data.doc.total_debit_transactions} {data.doc.total_debit_transactions === 1 ? _("transaction") : _("transactions")}) {_("Total Credits")} {formatCurrency(flt(data.doc.total_credits, 2), data.currency)} ({data.doc.total_credit_transactions} {data.doc.total_credit_transactions === 1 ? _("transaction") : _("transactions")}) {_("Closing Balance as of {}", [formatDate(data.doc.end_date, "Do MMMM YYYY")])} {formatCurrency(flt(data.doc.closing_balance, 2), data.currency)}
{_("Detected Amount Format")} {_("The amount format detected in the statement file. This is used to parse the deposit and withdrawal values from each row.")}
{data.doc.detected_amount_format}
{_("Detected Date Format")} {_("The date format detected in the statement file. This is used to parse the date values.")}
{dateFormat || data.date_format} (e.g.{" "} {formatDate(new Date(), dateFormat || "YYYY-MM-DD")})
{data.doc.status === "Not Started" ? <>

{_("Preview Transactions")}

{data.final_transactions?.length === 1 ? ( {_("We've found 1 transaction in the statement file that will be imported into the system. Please review the details below and click the 'Import' button to proceed.")} ) : ( {_("{0} transactions will be imported into the system. Please review the details below and click the 'Import' button to proceed.", [data.final_transactions?.length?.toString() || "0"])} )}
{_("Transactions to be imported into the system")} # {_("Date")} {_("Description")} {_("Ref.")} {_("Withdrawal")} {_("Deposit")} {data.final_transactions?.map((transaction, index) => ( {index + 1} {formatDate(transaction.date)} {transaction.description} {transaction.reference} {formatCurrency(transaction.withdrawal, data.currency)} {formatCurrency(transaction.deposit, data.currency)} ))}
: null}
) } const ConflictingTransactions = ({ transactions }: { transactions: GetStatementDetailsResponse["conflicting_transactions"] }) => { if (transactions.length === 0) { return null } return <> {_("Conflicting Transactions")} {transactions.length === 1 ? _("We've found 1 existing transaction in the system that conflicts with the transactions in the statement file. Are you sure you want to proceed with the import?") : _("We've found {0} existing transactions in the system that conflict with the transactions in the statement file. Are you sure you want to proceed with the import?", [transactions.length.toString()])}
{_("Conflicting Transactions")} {transactions.length === 1 ? _("We've found 1 existing transaction in the system that conflicts with the transactions in the statement file. Are you sure you want to proceed with the import?") : _("We've found {0} existing transactions in the system that conflict with the transactions in the statement file. Are you sure you want to proceed with the import?", [transactions.length.toString()])}
{_("Existing transactions in the system belonging to the same bank account and date range")} {_("Date")} {_("Description")} {_("Ref.")} {_("Withdrawal")} {_("Deposit")} {transactions.map((transaction) => ( {formatDate(transaction.date)} {transaction.description} {transaction.reference_number ? transaction.reference_number : "-"} {formatCurrency(transaction.withdrawal, transaction.currency)} {formatCurrency(transaction.deposit, transaction.currency)} {_("Open {0} in a new tab", [transaction.name])} ))}
} export default StatementDetails