@accounter/server
Version:
Accounter GraphQL server
61 lines (60 loc) • 2.61 kB
TypeScript
/**
* Document Aggregator
*
* Aggregates multiple documents from a single charge into a unified representation
* for matching purposes. Handles type priority filtering, business extraction,
* amount normalization, currency validation, date selection, and description concatenation.
*/
import { currency, document_type } from '../../documents/types.js';
import { AggregatedDocument } from '../types.js';
/**
* Minimal document interface for aggregation
* Based on database schema from accounter_schema.documents
* Note: Documents use charge_id for the FK
*/
export interface Document {
id: string;
charge_id: string | null;
creditor_id: string | null;
debtor_id: string | null;
currency_code: currency | null;
date: Date | null;
total_amount: number | null;
type: document_type;
serial_number: string | null;
image_url: string | null;
file_url: string | null;
}
/**
* Aggregate multiple documents into a single representation
*
* Per specification (section 4.2):
* 1. Filter by type priority: if both invoices AND receipts exist, use only invoices
* 2. Extract business ID from each document (creditor_id/debtor_id)
* 3. Normalize each amount based on business role and document type
* 4. Validate non-empty array
* 5. Check for mixed currencies → throw error
* 6. Check for multiple non-null business IDs → throw error
* 7. Sum all normalized amounts
* 8. Select latest date
* 9. Concatenate serial_number or file names with line breaks
* 10. Determine document type for result (use first after filtering)
*
* @param documents - Array of documents from a charge (use charge_id field for FK)
* @param adminBusinessId - Current admin business UUID for business extraction
* @returns Aggregated document data
*
* @throws {Error} If documents array is empty
* @throws {Error} If multiple different currencies exist
* @throws {Error} If multiple different non-null business IDs exist
* @throws {Error} If business extraction fails (propagates from extractDocumentBusiness)
* @throws {Error} If no valid date found in any document
*
* @example
* const aggregated = aggregateDocuments([
* { total_amount: 100, currency_code: 'USD', creditor_id: 'b1', debtor_id: 'u1', type: DocumentType.Invoice, ... },
* { total_amount: 50, currency_code: 'USD', creditor_id: 'b1', debtor_id: 'u1', type: DocumentType.Invoice, ... }
* ], 'u1');
* // Returns aggregated with normalized amounts summed
*/
export declare function aggregateDocuments(documents: Document[], adminBusinessId: string): Omit<AggregatedDocument, 'businessIsCreditor'>;