mirror of
https://github.com/marcogll/TaxHacker_s23.git
synced 2026-01-13 13:25:18 +00:00
fix: export tx more logs
This commit is contained in:
@@ -38,6 +38,9 @@ export async function GET(request: Request) {
|
|||||||
// Process transactions in chunks to avoid memory issues
|
// Process transactions in chunks to avoid memory issues
|
||||||
for (let i = 0; i < transactions.length; i += TRANSACTIONS_CHUNK_SIZE) {
|
for (let i = 0; i < transactions.length; i += TRANSACTIONS_CHUNK_SIZE) {
|
||||||
const chunk = transactions.slice(i, i + TRANSACTIONS_CHUNK_SIZE)
|
const chunk = transactions.slice(i, i + TRANSACTIONS_CHUNK_SIZE)
|
||||||
|
console.log(
|
||||||
|
`Processing transactions ${i + 1}-${Math.min(i + TRANSACTIONS_CHUNK_SIZE, transactions.length)} of ${transactions.length}`
|
||||||
|
)
|
||||||
|
|
||||||
for (const transaction of chunk) {
|
for (const transaction of chunk) {
|
||||||
const row: Record<string, unknown> = {}
|
const row: Record<string, unknown> = {}
|
||||||
@@ -90,8 +93,22 @@ export async function GET(request: Request) {
|
|||||||
throw new Error("Failed to create zip folder")
|
throw new Error("Failed to create zip folder")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let totalFilesProcessed = 0
|
||||||
|
let totalFilesToProcess = 0
|
||||||
|
|
||||||
|
// First count total files to process
|
||||||
|
for (const transaction of transactions) {
|
||||||
|
const transactionFiles = await getFilesByTransactionId(transaction.id, user.id)
|
||||||
|
totalFilesToProcess += transactionFiles.length
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Starting to process ${totalFilesToProcess} files in total`)
|
||||||
|
|
||||||
for (let i = 0; i < transactions.length; i += FILES_CHUNK_SIZE) {
|
for (let i = 0; i < transactions.length; i += FILES_CHUNK_SIZE) {
|
||||||
const chunk = transactions.slice(i, i + FILES_CHUNK_SIZE)
|
const chunk = transactions.slice(i, i + FILES_CHUNK_SIZE)
|
||||||
|
console.log(
|
||||||
|
`Processing files for transactions ${i + 1}-${Math.min(i + FILES_CHUNK_SIZE, transactions.length)} of ${transactions.length}`
|
||||||
|
)
|
||||||
|
|
||||||
for (const transaction of chunk) {
|
for (const transaction of chunk) {
|
||||||
const transactionFiles = await getFilesByTransactionId(transaction.id, user.id)
|
const transactionFiles = await getFilesByTransactionId(transaction.id, user.id)
|
||||||
@@ -108,6 +125,9 @@ export async function GET(request: Request) {
|
|||||||
for (const file of transactionFiles) {
|
for (const file of transactionFiles) {
|
||||||
const fullFilePath = fullPathForFile(user, file)
|
const fullFilePath = fullPathForFile(user, file)
|
||||||
if (await fileExists(fullFilePath)) {
|
if (await fileExists(fullFilePath)) {
|
||||||
|
console.log(
|
||||||
|
`Processing file ${++totalFilesProcessed}/${totalFilesToProcess}: ${file.filename} for transaction ${transaction.id}`
|
||||||
|
)
|
||||||
const fileData = await fs.readFile(fullFilePath)
|
const fileData = await fs.readFile(fullFilePath)
|
||||||
const fileExtension = path.extname(fullFilePath)
|
const fileExtension = path.extname(fullFilePath)
|
||||||
transactionFolder.file(
|
transactionFolder.file(
|
||||||
@@ -116,11 +136,15 @@ export async function GET(request: Request) {
|
|||||||
}${fileExtension}`,
|
}${fileExtension}`,
|
||||||
fileData
|
fileData
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
console.log(`Skipping missing file: ${file.filename} for transaction ${transaction.id}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`Finished processing all ${totalFilesProcessed} files`)
|
||||||
|
|
||||||
// Generate zip with progress tracking
|
// Generate zip with progress tracking
|
||||||
const zipContent = await zip.generateAsync({
|
const zipContent = await zip.generateAsync({
|
||||||
type: "uint8array",
|
type: "uint8array",
|
||||||
|
|||||||
@@ -36,14 +36,14 @@ export default async function FieldsSettingsPage() {
|
|||||||
{ key: "llm_prompt", label: "LLM Prompt", editable: true },
|
{ key: "llm_prompt", label: "LLM Prompt", editable: true },
|
||||||
{
|
{
|
||||||
key: "isVisibleInList",
|
key: "isVisibleInList",
|
||||||
label: "Show in transactions table",
|
label: "Always show in transactions table",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
editable: true,
|
editable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "isVisibleInAnalysis",
|
key: "isVisibleInAnalysis",
|
||||||
label: "Show in analysis form",
|
label: "Always show in analysis form",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
editable: true,
|
editable: true,
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import { Separator } from "@/components/ui/separator"
|
|||||||
import { useTransactionFilters } from "@/hooks/use-transaction-filters"
|
import { useTransactionFilters } from "@/hooks/use-transaction-filters"
|
||||||
import { Category, Field, Project } from "@/prisma/client"
|
import { Category, Field, Project } from "@/prisma/client"
|
||||||
import { formatDate } from "date-fns"
|
import { formatDate } from "date-fns"
|
||||||
import { Download, Loader2 } from "lucide-react"
|
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
const deselectedFields = ["files", "text"]
|
const deselectedFields = ["files", "text"]
|
||||||
@@ -42,49 +41,34 @@ export function ExportTransactionsDialog({
|
|||||||
)
|
)
|
||||||
const [includeAttachments, setIncludeAttachments] = useState(true)
|
const [includeAttachments, setIncludeAttachments] = useState(true)
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = () => {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
const exportWindow = window.open(
|
||||||
|
`/export/transactions?${new URLSearchParams({
|
||||||
|
search: exportFilters?.search || "",
|
||||||
|
dateFrom: exportFilters?.dateFrom || "",
|
||||||
|
dateTo: exportFilters?.dateTo || "",
|
||||||
|
ordering: exportFilters?.ordering || "",
|
||||||
|
categoryCode: exportFilters?.categoryCode || "",
|
||||||
|
projectCode: exportFilters?.projectCode || "",
|
||||||
|
fields: exportFields.join(","),
|
||||||
|
includeAttachments: includeAttachments.toString(),
|
||||||
|
}).toString()}`
|
||||||
|
)
|
||||||
|
|
||||||
try {
|
// Check if window was opened successfully
|
||||||
const response = await fetch(
|
if (!exportWindow) {
|
||||||
`/export/transactions?${new URLSearchParams({
|
|
||||||
search: exportFilters?.search || "",
|
|
||||||
dateFrom: exportFilters?.dateFrom || "",
|
|
||||||
dateTo: exportFilters?.dateTo || "",
|
|
||||||
ordering: exportFilters?.ordering || "",
|
|
||||||
categoryCode: exportFilters?.categoryCode || "",
|
|
||||||
projectCode: exportFilters?.projectCode || "",
|
|
||||||
fields: exportFields.join(","),
|
|
||||||
includeAttachments: includeAttachments.toString(),
|
|
||||||
}).toString()}`
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error("Export failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the filename from the Content-Disposition header
|
|
||||||
const contentDisposition = response.headers.get("Content-Disposition")
|
|
||||||
const filename = contentDisposition?.split("filename=")[1]?.replace(/"/g, "") || "transactions.zip"
|
|
||||||
|
|
||||||
// Create a blob from the response
|
|
||||||
const blob = await response.blob()
|
|
||||||
|
|
||||||
// Create a download link and trigger it
|
|
||||||
const url = window.URL.createObjectURL(blob)
|
|
||||||
const a = document.createElement("a")
|
|
||||||
a.href = url
|
|
||||||
a.download = filename
|
|
||||||
document.body.appendChild(a)
|
|
||||||
a.click()
|
|
||||||
window.URL.revokeObjectURL(url)
|
|
||||||
document.body.removeChild(a)
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Export failed:", error)
|
|
||||||
// You might want to show an error message to the user here
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Monitor the export window
|
||||||
|
const checkWindow = setInterval(() => {
|
||||||
|
if (exportWindow.closed) {
|
||||||
|
clearInterval(checkWindow)
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -92,9 +76,7 @@ export function ExportTransactionsDialog({
|
|||||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||||
<DialogContent className="max-w-xl">
|
<DialogContent className="max-w-xl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="text-2xl font-bold">
|
<DialogTitle className="text-2xl font-bold">Export {total} Transactions</DialogTitle>
|
||||||
Export {total} Transaction{total !== 1 ? "s" : ""}
|
|
||||||
</DialogTitle>
|
|
||||||
<DialogDescription>Export selected transactions and files as a CSV file or a ZIP archive</DialogDescription>
|
<DialogDescription>Export selected transactions and files as a CSV file or a ZIP archive</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
@@ -190,17 +172,7 @@ export function ExportTransactionsDialog({
|
|||||||
</div>
|
</div>
|
||||||
<DialogFooter className="sm:justify-end">
|
<DialogFooter className="sm:justify-end">
|
||||||
<Button type="button" onClick={handleSubmit} disabled={isLoading}>
|
<Button type="button" onClick={handleSubmit} disabled={isLoading}>
|
||||||
{isLoading ? (
|
{isLoading ? "Exporting..." : "Export Transactions"}
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
|
||||||
<span>Exporting...</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Download className="h-4 w-4" />
|
|
||||||
<span>Export Transactions</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./pgdata:/var/lib/postgresql/data
|
- ./pgdata:/var/lib/postgresql/data
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
logging:
|
logging:
|
||||||
driver: "local"
|
driver: "local"
|
||||||
options:
|
options:
|
||||||
|
|||||||
Reference in New Issue
Block a user