Add Documents tab and include document metadata in financial export
Validate / validate (push) Successful in 26s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 11:11:54 +07:00
parent 2489b092af
commit 5d9c0f0249
2 changed files with 79 additions and 2 deletions
+75 -1
View File
@@ -21,7 +21,9 @@ import {
users,
companyBankAccounts,
companyCards,
companyAddresses
companyAddresses,
companyDocuments,
companyDocumentVersions
} from '../db/schema.js';
import { csvBuild } from '$lib/utils/csv.js';
import { CARRIER_LABELS } from '../shipping/index.js';
@@ -74,6 +76,7 @@ export async function buildFinancialExport(
` company_bank_accounts.csv — company bank accounts`,
` company_cards.csv — company credit/debit cards (last 4 only)`,
` company_addresses.csv — legal/shipping/billing/other addresses`,
` company_documents.csv — uploaded document metadata (files not bundled)`,
` projects.csv — all projects (active + inactive)`,
` parties.csv — all customers/suppliers (incl. archived; see deletedAt)`,
` employees.csv — all employees (incl. terminated/archived)`,
@@ -210,6 +213,77 @@ export async function buildFinancialExport(
zip.file('company_addresses.csv', withBom(csvBuild(rows)));
}
// ── company_documents.csv ──────────────────────────
{
const docRows = await db
.select()
.from(companyDocuments)
.where(eq(companyDocuments.companyId, companyId))
.orderBy(asc(companyDocuments.category), asc(companyDocuments.title));
// Latest version per document (joined)
const latestByDoc = new Map<
string,
{
versionNumber: number;
fileName: string;
mimeType: string;
sizeBytes: number;
uploadedBy: string | null;
uploadedAt: Date;
}
>();
if (docRows.length > 0) {
const versionRows = await db
.select({
documentId: companyDocumentVersions.documentId,
versionNumber: companyDocumentVersions.versionNumber,
fileName: companyDocumentVersions.fileName,
mimeType: companyDocumentVersions.mimeType,
sizeBytes: companyDocumentVersions.sizeBytes,
uploadedBy: companyDocumentVersions.uploadedBy,
uploadedAt: companyDocumentVersions.uploadedAt
})
.from(companyDocumentVersions)
.where(
inArray(
companyDocumentVersions.documentId,
docRows.map((d) => d.id)
)
);
for (const v of versionRows) {
const existing = latestByDoc.get(v.documentId);
if (!existing || v.versionNumber > existing.versionNumber) {
latestByDoc.set(v.documentId, v);
}
}
}
const rows: unknown[][] = [
[
'id', 'category', 'customLabel', 'title', 'description', 'expiresAt',
'currentVersion', 'currentFilename', 'currentSizeBytes', 'currentMimeType',
'uploadedBy', 'uploadedAt', 'deletedAt', 'createdAt', 'updatedAt'
]
];
for (const d of docRows) {
const latest = latestByDoc.get(d.id);
rows.push([
d.id, d.category, d.customLabel ?? '', d.title, d.description ?? '',
d.expiresAt ?? '',
latest?.versionNumber ?? '',
latest?.fileName ?? '',
latest?.sizeBytes ?? '',
latest?.mimeType ?? '',
latest?.uploadedBy ?? '',
latest?.uploadedAt.toISOString() ?? '',
d.deletedAt ? d.deletedAt.toISOString() : '',
d.createdAt.toISOString(), d.updatedAt.toISOString()
]);
}
zip.file('company_documents.csv', withBom(csvBuild(rows)));
}
// ── projects.csv ────────────────────────────────────
const projectRows = await db
.select()
@@ -33,7 +33,10 @@
]
: []),
...(data.companyRoles.some((r) => r === 'admin' || r === 'manager' || r === 'accountant')
? [{ href: `/companies/${data.company.id}/profile`, label: 'Profile' }]
? [
{ href: `/companies/${data.company.id}/profile`, label: 'Profile' },
{ href: `/companies/${data.company.id}/documents`, label: 'Documents' }
]
: []),
...(data.companyRoles.includes('admin') || data.companyRoles.includes('accountant')
? [{ href: `/companies/${data.company.id}/export`, label: 'Export' }]