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 (
{direction === 'ltr' ? : }
{_("Back")}
{data.doc.status === 'Completed' ? {_("Completed")} :
{loading ? : null}
{loading ? _("Importing...") : _("Import {0} transactions", [data.final_transactions?.length?.toString() || "0"])}
}
{_("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()])}
{transactions.length > 1 ? _("View transactions") : _("View transaction")}
{_("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])}
))}
{_("Close")}
>
}
export default StatementDetails