import { ToolSet } from 'ai'; import { ArAgentsError } from '@ar-agents/core'; /** * SICORE types — federal income tax (Ganancias) retentions per RG 830/00. * * SICORE is the AFIP/ARCA system that agentes de retención use to file * monthly DDJJ of every retention they performed during the period. The * REAL retention happens at the moment of payment to a supplier; SICORE * is the reconciliation surface AFIP ingests. * * This package focuses on the per-payment math (what to retain on each * invoice) plus the monthly DDJJ assembly. The actual SICORE upload is * adapter territory because it requires AFIP-cert authenticated XML * submission, which lives outside the package boundary. * * Categorías cubiertas en v0.1 (las 4 más comunes para SaaS B2B): * * - "servicios" Locaciones de obra y/o servicios sin relación de * dependencia. Anexo II tipo de operación 36. Rate: * 2% inscripto / 28% no-inscripto (sobre excedente). * - "honorarios" Honorarios profesionales. Anexo II tipo 28. Tabla * escalonada para inscripto (0%-22%) y 28% no-insc. * - "bienes" Compraventa de cosas muebles. Anexo II tipo 78. * Rate: 2% inscripto / 10% no-inscripto. * - "alquileres" Locaciones de inmuebles urbanos. Anexo II tipo * 49. Rate: 6% inscripto / 28% no-inscripto. * * Categorías NO cubiertas en v0.1 (necesitan v0.2): * - Intereses (Anexo II 25) * - Honorarios directorio (Anexo II 22) * - Locaciones de inmuebles rurales (Anexo II 50) * - Honorarios sindicales (Anexo II 24) * - Y el resto del catálogo de Anexo II (≈80 tipos) * * Todos los montos en ARS centavos (integers). Las tablas y mínimos son * snapshot 2024-Q4 — el caller pasa la tabla vigente para el período. */ /** Tipos de operación cubiertos en v0.1. */ type SicoreCategory = "servicios" | "honorarios" | "bienes" | "alquileres"; /** Régimen del proveedor frente al impuesto. Inscripto = con CUIT * registrado y constancia activa. No-inscripto = sin constancia o * con CUIT vencido. Exento = con certificado de no-retención vigente * (cf. RG 830 art 38). */ type SupplierStatus = "inscripto" | "no_inscripto" | "exento"; /** * Una entrada de tabla de retención. Las tablas de Anexo II tienen una * estructura uniforme: un mínimo no imponible mensual + un rate (flat * para servicios/bienes/alquileres, escalonado para honorarios). Esta * shape cubre ambos casos: si `scale` está presente, el cálculo usa la * escala progresiva; si no, usa `flatRate`. */ interface SicoreRateEntry { category: SicoreCategory; status: SupplierStatus; /** Mínimo no imponible MENSUAL en centavos (acumulado por proveedor). */ minimumMonthlyCentavos: number; /** Rate plano (fracción) — usado cuando no hay `scale`. */ flatRate?: number | undefined; /** Escala progresiva (honorarios). Cada tramo aplica al EXCEDENTE del * mínimo, no al total. Tramos contiguos y crecientes. */ scale?: ReadonlyArray | undefined; /** Importe fijo a sumar tras aplicar el rate del tramo (honorarios). */ fixedAmountCentavos?: number | undefined; } interface SicoreScaleStep { /** Límite SUPERIOR del tramo en centavos (excedente sobre mínimo). El * tramo más alto lleva `Infinity`. */ upToCentavos: number; /** Rate del tramo, como fracción (0.06 = 6%). */ rate: number; /** Importe fijo del tramo (centavos), sumado al rate × excedente. */ fixedCentavos: number; } /** * Cálculo de retención individual. El llamador pasa el monto del pago * de HOY y, opcionalmente, lo ya pagado al mismo proveedor en el mes * (para la regla acumulativa). */ interface RetentionInput { category: SicoreCategory; status: SupplierStatus; /** CUIT del proveedor (con o sin guiones, 11 dígitos). */ supplierCuit: string; /** Monto del pago de hoy en centavos. */ paymentCentavos: number; /** Pagos acumulados al MISMO proveedor en el mes (centavos). Default 0. */ accumulatedMonthCentavos?: number | undefined; /** Retenciones ya practicadas al mismo proveedor en el mes (centavos). Default 0. */ alreadyRetainedThisMonthCentavos?: number | undefined; /** Fecha del pago (YYYY-MM-DD). Para audit + tabla lookup. */ paymentDate: string; /** Override de la tabla. Por defecto el package usa la tabla snapshot. */ rateTable?: ReadonlyArray | undefined; } interface RetentionResult { category: SicoreCategory; status: SupplierStatus; supplierCuit: string; paymentDate: string; /** Monto del pago de hoy. */ paymentCentavos: number; /** Monto acumulado en el mes (incluyendo hoy). */ accumulatedAfterPaymentCentavos: number; /** Mínimo no imponible aplicado. */ minimumMonthlyCentavos: number; /** Rate efectivo aplicado (weighted si hubo escala). */ effectiveRate: number; /** Retención teórica sobre el ACUMULADO. */ theoreticalRetentionCentavos: number; /** Retención ya practicada en el mes a este proveedor. */ alreadyRetainedThisMonthCentavos: number; /** Retención que se practica en este pago (lo que paga AFIP en SICORE). */ retentionAmountCentavos: number; /** Razón por la que no se retiene (si retentionAmountCentavos = 0). */ waiverReason?: "exento_certificate" | "below_minimum" | "already_satisfied" | undefined; } interface SicoreEntry { /** Ref id del comprobante / pago. */ comprobanteRef: string; /** Resultado de la retención. */ retention: RetentionResult; } interface SicoreDdjjArgs { /** YYYY-MM. */ period: string; /** CUIT del agente de retención. */ agentCuit: string; /** Todas las retenciones practicadas en el período. */ entries: ReadonlyArray; } interface SicoreDdjjResult { period: string; agentCuit: string; totals: { paymentCentavos: number; retentionCentavos: number; entryCount: number; }; byCategory: ReadonlyArray<{ category: SicoreCategory; paymentCentavos: number; retentionCentavos: number; entryCount: number; }>; bySupplier: ReadonlyArray<{ supplierCuit: string; paymentCentavos: number; retentionCentavos: number; entryCount: number; }>; entries: ReadonlyArray; } /** * Pure calculation primitives for SICORE / Ganancias retentions. * * The math is deterministic and offline. Given an input + a rate table, * `calculateRetention` returns exactly what AFIP expects on the * comprobante de retención. * * Two important nuances of RG 830/00: * * 1. ACUMULADO. The retention applies to the MONTHLY ACCUMULATED * amount paid to the same supplier — not to a single invoice. * The first payment of the month often retains $0 (under the * mínimo), and later payments retain the catch-up. * * 2. NETO YA RETENIDO. The retention amount for this payment equals * the theoretical retention on the accumulated minus retentions * already practiced this month. This way the cumulative retained * always matches the cumulative theoretical, even when monthly * payments straddle the threshold. * * If you skip these two rules, you'll over-retain on big single * payments and under-retain when payments straddle the threshold. */ /** * Calculate the SICORE retention for a single payment. * * The math: * accumulated_after = accumulated_before_today + payment * excedente = max(accumulated_after - mínimo, 0) * theoretical_retention = scale ? applyScale(excedente) : excedente × rate * retention_today = theoretical_retention - already_retained_this_month * * If `status` is "exento", retention is always 0. * If `accumulated_after < mínimo`, retention is 0 (below threshold). */ declare function calculateRetention(input: RetentionInput): RetentionResult; /** * Walk through a chronological stream of payments to the SAME supplier * and return one RetentionResult per payment, with the accumulator * advancing automatically. Use this when you have a flat list of * payments and don't want to bookkeep the running totals yourself. */ declare function calculateRetentionStream(payments: ReadonlyArray<{ category: SicoreCategory; status: SupplierStatus; supplierCuit: string; paymentCentavos: number; paymentDate: string; }>, rateTable?: ReadonlyArray): RetentionResult[]; declare function buildSicoreDdjj(args: SicoreDdjjArgs): SicoreDdjjResult; /** Convenience: pure helper to skip the typed input boilerplate. */ declare function quickRetention(category: SicoreCategory, status: SupplierStatus, paymentCentavos: number, options?: { supplierCuit?: string; paymentDate?: string; accumulatedMonthCentavos?: number; alreadyRetainedThisMonthCentavos?: number; }): number; declare function asEntry(comprobanteRef: string, retention: RetentionResult): SicoreEntry; /** * SICORE rate tables — snapshot 2024-Q4. * * IMPORTANT: these are SNAPSHOTS. Mínimos no imponibles and rate * scales are updated regularly (RG 5531/2024 was the last major * adjustment). Verify against the current AFIP/ARCA regulation before * filing. Override the table via `RetentionInput.rateTable` whenever * the period being calculated falls outside this snapshot. * * Source documents: * - RG 830/00 (régimen general) * - RG 5531/2024 (última actualización de mínimos no-imponibles) * - Anexo II tipos 28, 36, 49, 78 * * All amounts in ARS centavos (integers). Rates as fractions. */ /** * Default rate-table shipping with the package (2024-Q4 snapshot). * Combines all four categories. Override per-call when the period * falls outside this snapshot. */ declare const DEFAULT_RATE_TABLE: ReadonlyArray; /** Re-exported for callers that want to compose subsets. */ declare const SICORE_TABLES: { readonly servicios: readonly SicoreRateEntry[]; readonly honorarios: readonly SicoreRateEntry[]; readonly bienes: readonly SicoreRateEntry[]; readonly alquileres: readonly SicoreRateEntry[]; }; interface SicoreAdapter { /** * Submit a SICORE DDJJ to AFIP/ARCA. Returns an opaque receipt id * (typically the F.997 / F.744 acuse de recibo number) and the raw * AFIP response so the host can persist the audit trail. */ submitDdjj(ddjj: SicoreDdjjResult): Promise<{ receiptId: string; submittedAt: string; raw?: unknown; }>; } /** Default. Throws on every submission attempt. Safe for unit tests. */ declare class UnconfiguredSicoreAdapter implements SicoreAdapter { submitDdjj(): Promise; } /** * Drop-in tool collection for Vercel AI SDK 6+. Pair with an Agent. * * The tool layer leans heavily on the pure calc primitives in calc.ts * (calculateRetention, calculateRetentionStream, buildSicoreDdjj). The * adapter is only required for `sicore_submit_ddjj` (currently throws * by default; wire a custom adapter if your host has AFIP creds). */ interface SicoreToolsOptions { /** Adapter for submission. Defaults to UnconfiguredSicoreAdapter. */ adapter?: SicoreAdapter; /** Override the in-package rate-table snapshot. */ rateTable?: ReadonlyArray; /** Optional subset of tools to expose. */ include?: ReadonlyArray; } declare const ALL_TOOL_NAMES: readonly ["sicore_calculate_retention", "sicore_calculate_retention_stream", "sicore_build_ddjj", "sicore_submit_ddjj"]; type SicoreToolName = (typeof ALL_TOOL_NAMES)[number]; declare function sicoreTools(opts?: SicoreToolsOptions): ToolSet; /** * Error taxonomy for @ar-agents/sicore. * * Agents should distinguish: * - validation errors (bad input, do NOT retry) * - rate-table errors (no entry for category/status, surface to operator) * - unconfigured errors (adapter not wired, surface to operator) * * `SicoreError` extends `ArAgentsError` from `@ar-agents/core` so the * `@ar-agents/*` family shares one error contract. */ declare class SicoreError extends ArAgentsError { constructor(message: string, code?: string, context?: Record); } /** Bad input (e.g. negative payment, invalid CUIT). Do NOT retry. */ declare class SicoreValidationError extends SicoreError { readonly field: string; constructor(field: string, message: string); } /** No rate-table entry for the (category, status) pair the caller asked * for. Usually means the table is incomplete for the supplier's * situation. */ declare class SicoreRateNotFoundError extends SicoreError { readonly category: string; readonly status: string; constructor(category: string, status: string); } /** Adapter not wired (no submission target). Surface to the operator. */ declare class SicoreUnconfiguredError extends SicoreError { readonly operation: string; constructor(operation: string, label?: string); } export { ALL_TOOL_NAMES, DEFAULT_RATE_TABLE, type RetentionInput, type RetentionResult, SICORE_TABLES, type SicoreAdapter, type SicoreCategory, type SicoreDdjjArgs, type SicoreDdjjResult, type SicoreEntry, SicoreError, type SicoreRateEntry, SicoreRateNotFoundError, type SicoreScaleStep, type SicoreToolName, type SicoreToolsOptions, SicoreUnconfiguredError, SicoreValidationError, type SupplierStatus, UnconfiguredSicoreAdapter, asEntry, buildSicoreDdjj, calculateRetention, calculateRetentionStream, quickRetention, sicoreTools };