// PaymentAllocator — UI del reparto de un pago entre los documentos abiertos de // la contraparte (cobro multi-factura / REP, CxP «Aplicar pago»). Las reglas // son las de primitives/allocation (allocatePayment / validateAllocation); aquí // solo se pintan y se editan. Por defecto reparte solo, del más vencido al más // reciente; al teclear un monto pasa a manual sin perder lo ya repartido. import { useTranslation } from 'react-i18next' import { Badge, Button } from '@asteby/metacore-ui/primitives' import { Input } from '@asteby/metacore-ui' import type { AllocationResult, AllocationStrategy, OpenDocument } from '../primitives/allocation' import { manualFromAllocations, overdueDays } from './document-editor-model' import { useFormatter } from './format' export interface PaymentAllocatorValue { strategy: AllocationStrategy manual: Record } export interface PaymentAllocatorProps { documents: OpenDocument[] /** Resultado de `allocatePayment(amount, documents, value.strategy, value.manual)`. */ result: AllocationResult value: PaymentAllocatorValue onChange: (next: PaymentAllocatorValue) => void currency?: string loading?: boolean readOnly?: boolean /** Hoy (para los días de atraso; inyectable en tests). */ today?: Date } const num = (s: string): number => (s.trim() === '' ? 0 : Number(s.replace(',', '.')) || 0) export function PaymentAllocator({ documents, result, value, onChange, currency, loading, readOnly, today }: PaymentAllocatorProps) { const { t } = useTranslation() const fmt = useFormatter({ currency }) const byDoc = new Map(result.allocations.map((a) => [a.document_id, a])) if (loading) { return

{t('paymentAllocator.loading', { defaultValue: 'Buscando documentos con saldo…' })}

} if (documents.length === 0) { return (

{t('paymentAllocator.empty', { defaultValue: 'No hay documentos con saldo pendiente.' })}

) } const setAmount = (id: string, amount: number) => onChange({ strategy: 'manual', manual: { ...manualFromAllocations(result.allocations), [id]: amount } }) return (
{value.strategy === 'manual' ? t('paymentAllocator.manual', { defaultValue: 'Reparto manual' }) : t('paymentAllocator.auto', { defaultValue: 'Se aplica primero a lo más vencido' })} {!readOnly && value.strategy === 'manual' && ( )}
) }